home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / sd-26.zip / sdconc.c < prev    next >
C/C++ Source or Header  |  1992-09-09  |  100KB  |  2,146 lines

  1. /* SD -- square dance caller's helper.
  2.  
  3.     Copyright (C) 1990, 1991, 1992  William B. Ackerman.
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     This is for version 25. */
  20.  
  21. /* This defines the following functions:
  22.    normalize_concentric
  23.    normalize_setup
  24.    concentric_move
  25.    merge_setups
  26.    on_your_own_move
  27.    so_and_so_only_move
  28. */
  29.  
  30. #include "sd.h"
  31.  
  32.  
  33. typedef enum {
  34.    analyzer_NORMAL,
  35.    analyzer_CHECKPT,
  36.    analyzer_2X6,
  37.    analyzer_6X2,
  38.    analyzer_STAR12,
  39.    analyzer_SINGLE,
  40.    analyzer_VERTICAL6,
  41.    analyzer_LATERAL6,
  42.    analyzer_DIAMOND_LINE } analyzer_kind;
  43.  
  44.  
  45. static void normalize_4x4(setup *stuff)
  46.  
  47. {
  48.    if (!(stuff->people[0].id1 | stuff->people[4].id1 | stuff->people[8].id1 | stuff->people[12].id1)) {
  49.       if (!(stuff->people[5].id1 | stuff->people[6].id1 | stuff->people[13].id1 | stuff->people[14].id1)) {
  50.          stuff->kind = s2x4;
  51.          (void) copy_person(stuff, 4, stuff, 2);       /* careful -- order is important */
  52.          (void) copy_person(stuff, 5, stuff, 7);
  53.          (void) copy_person(stuff, 2, stuff, 3);
  54.          (void) copy_person(stuff, 3, stuff, 1);
  55.          (void) copy_person(stuff, 0, stuff, 10);
  56.          (void) copy_person(stuff, 1, stuff, 15);
  57.          (void) copy_person(stuff, 6, stuff, 11);
  58.          (void) copy_person(stuff, 7, stuff, 9);
  59.       }
  60.       else if (!(stuff->people[1].id1 | stuff->people[2].id1 | stuff->people[9].id1 | stuff->people[10].id1)) {
  61.          stuff->kind = s2x4;
  62.          stuff->rotation++;
  63.          (void) copy_rot(stuff, 1, stuff, 3, 033);     /* careful -- order is important */
  64.          (void) copy_rot(stuff, 2, stuff, 7, 033);
  65.          (void) copy_rot(stuff, 3, stuff, 5, 033);
  66.          (void) copy_rot(stuff, 4, stuff, 6, 033);
  67.          (void) copy_rot(stuff, 0, stuff, 14, 033);
  68.          (void) copy_rot(stuff, 5, stuff, 11, 033);
  69.          (void) copy_rot(stuff, 6, stuff, 15, 033);
  70.          (void) copy_rot(stuff, 7, stuff, 13, 033);
  71.       }
  72.    }
  73. }
  74.  
  75.  
  76. static void normalize_blob(setup *stuff)
  77.  
  78. {
  79.    if (!(stuff->people[0].id1 | stuff->people[1].id1 | stuff->people[12].id1 | stuff->people[13].id1)) {
  80.       stuff->kind = s4x6;
  81.       (void) copy_person(stuff, 13, stuff, 9);         /* careful -- order is important */
  82.       (void) copy_person(stuff, 9, stuff, 23);
  83.       (void) copy_person(stuff, 23, stuff, 7);
  84.       (void) copy_person(stuff, 7, stuff, 4);
  85.       (void) copy_person(stuff, 4, stuff, 3);
  86.       (void) copy_person(stuff, 3, stuff, 2);
  87.       (void) copy_person(stuff, 2, stuff, 22);
  88.       (void) copy_person(stuff, 22, stuff, 8);
  89.       (void) copy_person(stuff, 8, stuff, 5);
  90.       (void) copy_person(stuff, 1, stuff, 21);
  91.       (void) copy_person(stuff, 21, stuff, 11);
  92.       (void) copy_person(stuff, 11, stuff, 19);
  93.       (void) copy_person(stuff, 19, stuff, 16);
  94.       (void) copy_person(stuff, 16, stuff, 15);
  95.       (void) copy_person(stuff, 15, stuff, 14);
  96.       (void) copy_person(stuff, 14, stuff, 10);
  97.       (void) copy_person(stuff, 10, stuff, 20);
  98.       (void) copy_person(stuff, 20, stuff, 17);
  99.  
  100.       clear_person(stuff, 5);
  101.       clear_person(stuff, 17);
  102.    }
  103.    else if (!(stuff->people[6].id1 | stuff->people[7].id1 | stuff->people[18].id1 | stuff->people[19].id1)) {
  104.       stuff->kind = s4x6;
  105.       stuff->rotation++;
  106.       (void) copy_rot(stuff, 18, stuff, 0, 033);       /* careful -- order is important */
  107.       (void) copy_rot(stuff, 7, stuff, 10, 033);
  108.       (void) copy_rot(stuff, 10, stuff, 2, 033);
  109.       (void) copy_rot(stuff, 2, stuff, 4, 033);
  110.       (void) copy_rot(stuff, 4, stuff, 9, 033);
  111.       (void) copy_rot(stuff, 9, stuff, 5, 033);
  112.       (void) copy_rot(stuff, 6, stuff, 12, 033);
  113.       (void) copy_rot(stuff, 19, stuff, 22, 033);
  114.       (void) copy_rot(stuff, 22, stuff, 14, 033);
  115.       (void) copy_rot(stuff, 14, stuff, 16, 033);
  116.       (void) copy_rot(stuff, 16, stuff, 21, 033);
  117.       (void) copy_rot(stuff, 21, stuff, 17, 033);
  118.  
  119.       (void) copy_rot(stuff, 0, stuff, 3, 033);
  120.       (void) copy_rot(stuff, 3, stuff, 8, 033);
  121.       (void) copy_rot(stuff, 8, stuff, 11, 033);
  122.       (void) copy_rot(stuff, 11, stuff, 1, 033);
  123.       (void) copy_person(stuff, 1, stuff, 0);
  124.  
  125.       (void) copy_rot(stuff, 0, stuff, 23, 033);
  126.       (void) copy_rot(stuff, 23, stuff, 13, 033);
  127.       (void) copy_rot(stuff, 13, stuff, 15, 033);
  128.       (void) copy_rot(stuff, 15, stuff, 20, 033);
  129.       (void) copy_person(stuff, 20, stuff, 0);
  130.  
  131.       clear_person(stuff, 0);
  132.       clear_person(stuff, 5);
  133.       clear_person(stuff, 12);
  134.       clear_person(stuff, 17);
  135.    }
  136. }
  137.  
  138.  
  139.  
  140. static void normalize_4x6(setup *stuff)
  141.  
  142. {
  143.    if (!(stuff->people[0].id1 | stuff->people[11].id1 | stuff->people[18].id1 | stuff->people[17].id1 |
  144.             stuff->people[5].id1 | stuff->people[6].id1 | stuff->people[23].id1 | stuff->people[12].id1)) {
  145.       stuff->kind = s4x4;
  146.       (void) copy_person(stuff, 6, stuff, 15);         /* careful -- order is important */
  147.       (void) copy_person(stuff, 15, stuff, 9);
  148.       (void) copy_person(stuff, 9, stuff, 19);
  149.       (void) copy_person(stuff, 11, stuff, 20);
  150.       (void) copy_person(stuff, 5, stuff, 14);
  151.       (void) copy_person(stuff, 14, stuff, 3);
  152.       (void) copy_person(stuff, 3, stuff, 8);
  153.       (void) copy_person(stuff, 8, stuff, 16);
  154.       (void) copy_person(stuff, 12, stuff, 1);
  155.       (void) copy_person(stuff, 1, stuff, 7);
  156.       (void) copy_person(stuff, 7, stuff, 21);
  157.       (void) copy_person(stuff, 0, stuff, 4);
  158.       (void) copy_person(stuff, 4, stuff, 13);
  159.       (void) copy_person(stuff, 13, stuff, 2);
  160.       (void) copy_person(stuff, 2, stuff, 22);
  161.  
  162.       canonicalize_rotation(stuff);
  163.    }
  164.    else if (!(stuff->people[0].id1 | stuff->people[1].id1 | stuff->people[2].id1 | stuff->people[3].id1 |
  165.             stuff->people[4].id1 | stuff->people[5].id1 | stuff->people[17].id1 | stuff->people[16].id1 |
  166.             stuff->people[15].id1 | stuff->people[14].id1 | stuff->people[13].id1 | stuff->people[12].id1)) {
  167.       stuff->kind = s2x6;
  168.  
  169.       (void) copy_person(stuff, 0, stuff, 11);         /* careful -- order is important */
  170.       (void) copy_person(stuff, 11, stuff, 18);
  171.       (void) copy_person(stuff, 1, stuff, 10);
  172.       (void) copy_person(stuff, 10, stuff, 19);
  173.       (void) copy_person(stuff, 2, stuff, 9);
  174.       (void) copy_person(stuff, 9, stuff, 20);
  175.       (void) copy_person(stuff, 3, stuff, 8);
  176.       (void) copy_person(stuff, 8, stuff, 21);
  177.       (void) copy_person(stuff, 4, stuff, 7);
  178.       (void) copy_person(stuff, 7, stuff, 22);
  179.       (void) copy_person(stuff, 5, stuff, 6);
  180.       (void) copy_person(stuff, 6, stuff, 23);
  181.    }
  182. }
  183.  
  184.  
  185.  
  186. static void normalize_3dmd(setup *stuff)
  187.  
  188. {
  189.    setup temp;
  190.  
  191.    if (!(stuff->people[0].id1 | stuff->people[2].id1 | stuff->people[6].id1 | stuff->people[8].id1)) {
  192.       temp = *stuff;
  193.  
  194.       stuff->kind = s_3x1dmd;
  195.       (void) copy_person(stuff, 0, &temp, 9);
  196.       (void) copy_person(stuff, 6, &temp, 5);
  197.       (void) copy_person(stuff, 5, &temp, 4);
  198.       (void) copy_person(stuff, 4, &temp, 3);
  199.       (void) copy_person(stuff, 3, &temp, 1);
  200.       (void) copy_person(stuff, 1, &temp, 10);
  201.       (void) copy_person(stuff, 2, &temp, 11);
  202.    }
  203. }
  204.  
  205.  
  206.  
  207. static void normalize_4dmd(setup *stuff)
  208.  
  209. {
  210.    setup temp;
  211.  
  212.    if (!(stuff->people[0].id1 | stuff->people[3].id1 | stuff->people[4].id1 | stuff->people[5].id1 |
  213.             stuff->people[8].id1 | stuff->people[11].id1 | stuff->people[12].id1 | stuff->people[13].id1)) {
  214.  
  215.       /* Danger!  If the people were in side-by-side quarter-tags, turning this into
  216.          a single quarter-tag would require that the outsides slide together.  That
  217.          would be wrong.  The bug show up in cases like
  218.             1P2P; pass the ocean; swing and mix; follow thru; truck twice;
  219.             split phantom twin boxes sets in motion.
  220.          So, if people do not have diamond-like orientation, we go into an "H". */
  221.  
  222.       if (!(((stuff->people[6].id1 | stuff->people[7].id1 | stuff->people[14].id1 | stuff->people[15].id1) & 1) |
  223.             ((stuff->people[1].id1 | stuff->people[2].id1 | stuff->people[9].id1 | stuff->people[10].id1) & 010))) {
  224.          temp = *stuff;
  225.  
  226.          stuff->kind = s_qtag;
  227.          (void) copy_person(stuff, 0, &temp, 1);
  228.          (void) copy_person(stuff, 1, &temp, 2);
  229.          (void) copy_person(stuff, 2, &temp, 6);
  230.          (void) copy_person(stuff, 3, &temp, 7);
  231.          (void) copy_person(stuff, 4, &temp, 9);
  232.          (void) copy_person(stuff, 5, &temp, 10);
  233.          (void) copy_person(stuff, 6, &temp, 14);
  234.          (void) copy_person(stuff, 7, &temp, 15);
  235.       }
  236.       else {
  237.          temp = *stuff;
  238.          clear_people(stuff);
  239.  
  240.          stuff->kind = s3x4;
  241.          (void) copy_person(stuff, 0, &temp, 1);
  242.          (void) copy_person(stuff, 3, &temp, 2);
  243.          (void) copy_person(stuff, 4, &temp, 6);
  244.          (void) copy_person(stuff, 5, &temp, 7);
  245.          (void) copy_person(stuff, 6, &temp, 9);
  246.          (void) copy_person(stuff, 9, &temp, 10);
  247.          (void) copy_person(stuff, 10, &temp, 14);
  248.          (void) copy_person(stuff, 11, &temp, 15);
  249.       }
  250.    }
  251.    else if (!(stuff->people[0].id1 | stuff->people[1].id1 | stuff->people[2].id1 | stuff->people[3].id1 |
  252.             stuff->people[8].id1 | stuff->people[9].id1 | stuff->people[10].id1 | stuff->people[11].id1)) {
  253.       temp = *stuff;
  254.  
  255.       stuff->kind = s1x8;
  256.       (void) copy_person(stuff, 0, &temp, 12);
  257.       (void) copy_person(stuff, 1, &temp, 13);
  258.       (void) copy_person(stuff, 2, &temp, 15);
  259.       (void) copy_person(stuff, 3, &temp, 14);
  260.       (void) copy_person(stuff, 4, &temp, 4);
  261.       (void) copy_person(stuff, 5, &temp, 5);
  262.       (void) copy_person(stuff, 6, &temp, 7);
  263.       (void) copy_person(stuff, 7, &temp, 6);
  264.    }
  265.    else if (!(stuff->people[4].id1 | stuff->people[5].id1 | stuff->people[6].id1 | stuff->people[7].id1 |
  266.             stuff->people[12].id1 | stuff->people[13].id1 | stuff->people[14].id1 | stuff->people[15].id1)) {
  267.       temp = *stuff;
  268.       clear_people(stuff);
  269.  
  270.       stuff->kind = s4x4;
  271.       (void) copy_person(stuff, 12, &temp, 0);
  272.       (void) copy_person(stuff, 13, &temp, 1);
  273.       (void) copy_person(stuff, 14, &temp, 2);
  274.       (void) copy_person(stuff, 0, &temp, 3);
  275.       (void) copy_person(stuff, 4, &temp, 8);
  276.       (void) copy_person(stuff, 5, &temp, 9);
  277.       (void) copy_person(stuff, 6, &temp, 10);
  278.       (void) copy_person(stuff, 8, &temp, 11);
  279.  
  280.       canonicalize_rotation(stuff);
  281.    }
  282. }
  283.  
  284.  
  285. /* See if this 2x6 is actually occupied only in spots of a 2x4. */
  286.  
  287. static void normalize_2x6(setup *stuff)
  288.  
  289. {
  290.    if (!(stuff->people[0].id1 | stuff->people[5].id1 | stuff->people[6].id1 | stuff->people[11].id1)) {
  291.       stuff->kind = s2x4;
  292.       (void) copy_person(stuff, 0, stuff, 1);            /* careful -- order is important */
  293.       (void) copy_person(stuff, 1, stuff, 2);
  294.       (void) copy_person(stuff, 2, stuff, 3);
  295.       (void) copy_person(stuff, 3, stuff, 4);
  296.       (void) copy_person(stuff, 4, stuff, 7);
  297.       (void) copy_person(stuff, 5, stuff, 8);
  298.       (void) copy_person(stuff, 6, stuff, 9);
  299.       (void) copy_person(stuff, 7, stuff, 10);
  300.    }
  301. }
  302.  
  303.  
  304. /* See if this 2x8 is actually occupied only in spots of a 2x6. */
  305.  
  306. static void normalize_2x8(setup *s, setup *result)
  307.  
  308. {
  309.    if (!(s->people[7].id1 | s->people[8].id1 | s->people[0].id1 | s->people[15].id1)) {
  310.       result->kind = s2x6;
  311.       result->rotation = s->rotation;
  312.       (void) copy_person(result, 0, s, 1);
  313.       (void) copy_person(result, 1, s, 2);
  314.       (void) copy_person(result, 2, s, 3);
  315.       (void) copy_person(result, 3, s, 4);
  316.       (void) copy_person(result, 4, s, 5);
  317.       (void) copy_person(result, 5, s, 6);
  318.       (void) copy_person(result, 6, s, 9);
  319.       (void) copy_person(result, 7, s, 10);
  320.       (void) copy_person(result, 8, s, 11);
  321.       (void) copy_person(result, 9, s, 12);
  322.       (void) copy_person(result, 10, s, 13);
  323.       (void) copy_person(result, 11, s, 14);
  324.       return;
  325.    }
  326.    *result = *s;
  327. }
  328.  
  329.  
  330.  
  331. /* Check whether "C1 phantom" setup is only occupied in 2x4 spots, and fix it if so. */
  332.  
  333. static void normalize_c1_phan(setup *stuff)
  334.  
  335. {
  336.    if (!(stuff->people[1].id1 | stuff->people[3].id1 | stuff->people[4].id1 | stuff->people[6].id1 |
  337.             stuff->people[9].id1 | stuff->people[11].id1 | stuff->people[12].id1 | stuff->people[14].id1)) {
  338.       stuff->kind = s2x4;
  339.       (void) copy_person(stuff, 1, stuff, 2);                /* careful -- order is important */
  340.       (void) copy_person(stuff, 2, stuff, 7);
  341.       (void) copy_person(stuff, 3, stuff, 5);
  342.       (void) copy_person(stuff, 4, stuff, 8);
  343.       (void) copy_person(stuff, 5, stuff, 10);
  344.       (void) copy_person(stuff, 6, stuff, 15);
  345.       (void) copy_person(stuff, 7, stuff, 13);
  346.    }
  347.    else if (!(stuff->people[0].id1 | stuff->people[2].id1 | stuff->people[5].id1 | stuff->people[7].id1 |
  348.             stuff->people[8].id1 | stuff->people[10].id1 | stuff->people[13].id1 | stuff->people[15].id1)) {
  349.       stuff->kind = s2x4;
  350.       stuff->rotation++;
  351.       (void) copy_rot(stuff, 7, stuff, 1, 033);        /* careful -- order is important */
  352.       (void) copy_rot(stuff, 0, stuff, 4, 033);
  353.       (void) copy_rot(stuff, 2, stuff, 11, 033);
  354.       (void) copy_rot(stuff, 1, stuff, 6, 033);
  355.       (void) copy_rot(stuff, 6, stuff, 3, 033);
  356.       (void) copy_rot(stuff, 3, stuff, 9, 033);
  357.       (void) copy_rot(stuff, 4, stuff, 12, 033);
  358.       (void) copy_rot(stuff, 5, stuff, 14, 033);
  359.    }
  360. }
  361.  
  362.  
  363.  
  364.  
  365.  
  366. typedef struct {
  367.    veryshort mapin[8];
  368.    veryshort mapout[8];
  369.    short inlimit;
  370.    short outlimit;
  371.    setup_kind bigsetup;
  372.    setup_kind insetup;
  373.    setup_kind outsetup;
  374.    int bigsize;
  375.    int inner_rot;    /* 1 if inner setup is rotated CCW relative to big setup */
  376.    int outer_rot;    /* 1 if outer setup is rotated CCW relative to big setup */
  377.    int mapelong;
  378.    } cm_thing;
  379.  
  380. /*                                                                                                         mapelong --------|
  381.                                                                                                           outer_rot -----|  |
  382.                                                                                                    inner_rot ---------|  |  |
  383.                                                              outlimit -----|                          bigsize ----|   |  |  |
  384.                                   mapin           mapout       inlimit -|  |  bigsetup      insetup  outsetup     |   |  |  |   */
  385.  
  386. static cm_thing map1x2_1x2 =        {{1, 3},       {0, 2},              2, 2, s1x4,           s_1x2,    s_1x2,    4,  0, 0, 0};
  387. static cm_thing oddmap1x2_1x2 =     {{3, 1},       {0, 2},              2, 2, sdmd,           s_1x2,    s_1x2,    4,  1, 0, 0};
  388. static cm_thing mapdmd_dmd =        {{1, 3, 5, 7}, {0, 2, 4, 6},        4, 4, s_crosswave,    sdmd,     sdmd,     8,  0, 0, 9};
  389. static cm_thing oddmapdmd_1x4 =     {{1, 2, 5, 6}, {7, 0, 3, 4},        4, 4, s_3x1dmd,       s1x4,     sdmd,     8,  0, 1, 9};
  390. static cm_thing mapdmd_1x4 =        {{1, 2, 5, 6}, {0, 3, 4, 7},        4, 4, s_3x1dmd,       s1x4,     sdmd,     8,  0, 0, 9};
  391. static cm_thing oddmap_s_dmd_1x4 =  {{1, 2, 5, 6}, {7, 0, 3, 4},        4, 4, s_wingedstar,   s1x4,     sdmd,     8,  0, 1, 9};
  392. static cm_thing map_s_dmd_1x4 =     {{1, 2, 5, 6}, {0, 3, 4, 7},        4, 4, s_wingedstar,   s1x4,     sdmd,     8,  0, 0, 9};
  393. static cm_thing map_cs_1x4_dmd =    {{0, 3, 4, 7}, {1, 2, 5, 6},        4, 4, s_wingedstar,   sdmd,     s1x4,     8,  0, 0, 9};
  394. static cm_thing oddmap_s_star_1x4 = {{1, 2, 5, 6}, {7, 0, 3, 4},        4, 4, s_wingedstar,   s1x4,     s_star,   8,  0, 1, 9};
  395. static cm_thing map_s_star_1x4 =    {{1, 2, 5, 6}, {0, 3, 4, 7},        4, 4, s_wingedstar,   s1x4,     s_star,   8,  0, 0, 9};
  396. static cm_thing oddmap_s_short_1x6 = {{1, 2, 4, 7, 8, 10},
  397.                                              {11, 0, 3, 5, 6, 9},       6, 6, s_wingedstar12, s_1x6,    s_short6, 12, 0, 1, 9};
  398. static cm_thing map_spec_star12 =   {{2, 3, 4, 11}, {0, 1, 6, 7},       4, 4, s_wingedstar12, s_star,   s1x4,     12, 0, 0, 0};
  399. static cm_thing map_spec_star12v =  {{11, 2, 3, 4}, {0, 1, 6, 7},       4, 4, s_wingedstar12, s_star,   s1x4,     12, 1, 0, 0};
  400. static cm_thing mapdmd_2x2h =       {{1, 3, 5, 7}, {0, 2, 4, 6},        4, 4, s_galaxy,       s2x2,     sdmd,     8,  0, 0, 9};
  401. static cm_thing mapdmd_2x2v =       {{7, 1, 3, 5}, {0, 2, 4, 6},        4, 4, s_galaxy,       s2x2,     sdmd,     8,  1, 0, 9};
  402. static cm_thing map2x3_1x2 =        {{11, 5}, {0, 1, 2, 6, 7, 8},       2, 6, s_3dmd,         s_1x2,    s_2x3,    12, 0, 0, 9};
  403. static cm_thing map1x4_1x4 =        {{3, 2, 7, 6}, {0, 1, 4, 5},        4, 4, s1x8,           s1x4,     s1x4,     8,  0, 0, 0};
  404. static cm_thing oddmap1x4_1x4 =     {{6, 7, 2, 3}, {0, 1, 4, 5},        4, 4, s_crosswave,    s1x4,     s1x4,     8,  1, 0, 0};
  405. static cm_thing map2x3_2x3 = {{8, 11, 1, 2, 5, 7}, {9, 10, 0, 3, 4, 6}, 6, 6, s3x4,           s_2x3,    s_2x3,    12, 1, 1, 1};
  406. static cm_thing map1x2_bone6 = {{1, 7, 6, 5, 3, 2}, {0, 4},             6, 2, s_ptpd,         s_bone6,  s_1x2,    8,  0, 0, 0};
  407. static cm_thing map1x6_1x2 = {{2, 6}, {0, 1, 3, 4, 5, 7},               2, 6, s1x8,           s_1x2,    s_1x6,    8,  0, 0, 0};
  408. static cm_thing mapbone6_1x2 = {{7, 3}, {0, 1, 2, 4, 5, 6},             2, 6, s_bone,         s_1x2,    s_bone6,  8,  0, 0, 0};
  409. static cm_thing map1x4_1x4_rc = {{0, 2, 4, 6}, {1, 3, 5, 7},            4, 4, s1x8,           s1x4,     s1x4,     8,  0, 0, 0};
  410. static cm_thing map1x2_bone6_rc = {{0, 1, 3, 4, 5, 7}, {6, 2},          6, 2, s_bone,         s_bone6,  s_1x2,    8,  0, 0, 0};
  411. static cm_thing map2x2_dmd_rc = {{7, 1, 3, 5}, {0, 2, 4, 6},            4, 4, s_spindle,      sdmd,     s2x2,     8,  0, 0, 0};
  412. static cm_thing map2x2_1x4_rc = {{0, 2, 4, 6}, {1, 7, 5, 3},            4, 4, s_ptpd,         s1x4,     s2x2,     8,  0, 0, 0};
  413. static cm_thing oddmap2x2_1x4_rc = {{0, 2, 4, 6}, {3, 1, 7, 5},         4, 4, s_ptpd,         s1x4,     s2x2,     8,  0, 1, 9};
  414. static cm_thing map1x2_2x3 = {{0, 1, 2, 4, 5, 6}, {7, 3},               6, 2, s_spindle,      s_2x3,    s_1x2,    8,  0, 0, 0};
  415. static cm_thing map1x2_short6 = {{1, 2, 3, 5, 6, 7}, {0, 4},            6, 2, s_galaxy,       s_short6, s_1x2,    8,  0, 0, 0};
  416. static cm_thing mapshort6_1x2h = {{5, 1}, {6, 7, 0, 2, 3, 4},           2, 6, s_spindle,      s_1x2,    s_short6, 8,  1, 1, 1};
  417. static cm_thing mapshort6_1x2v = {{7, 3}, {5, 6, 0, 1, 2, 4},           2, 6, s_hrglass,      s_1x2,    s_short6, 8,  1, 1, 0};
  418. static cm_thing mapstar_2x2 = {{1, 3, 5, 7}, {0, 2, 4, 6},              4, 4, s_galaxy,       s2x2,     s_star,   8,  0, 0, 0};
  419. static cm_thing map1x2_1x6 = {{1, 3, 2, 5, 7, 6}, {0, 4},               6, 2, s1x8,           s_1x6,    s_1x2,    8,  0, 0, 0};
  420. static cm_thing oddmap1x2_1x6 = {{0, 1, 2, 4, 5, 6}, {7, 3},            6, 2, s_3x1dmd,       s_1x6,    s_1x2,    12, 0, 1, 0};
  421. static cm_thing map1x4_2x2 = {{0, 1, 4, 5}, {6, 7, 2, 3},               4, 4, s_rigger,       s2x2,     s1x4,     8,  0, 0, 0};
  422. static cm_thing oddmap1x4_2x2 = {{5, 0, 1, 4}, {6, 7, 2, 3},            4, 4, s_rigger,       s2x2,     s1x4,     8,  1, 0, 0};
  423. static cm_thing map1x4_star = {{2, 3, 6, 7}, {0, 1, 4, 5},              4, 4, s_wingedstar,   s_star,   s1x4,     8,  0, 0, 0};
  424. static cm_thing oddmap1x4_star = {{7, 2, 3, 6}, {0, 1, 4, 5},           4, 4, s_wingedstar,   s_star,   s1x4,     8,  1, 0, 0};
  425. static cm_thing map2x2_dmd = {{6, 3, 2, 7}, {0, 1, 4, 5},               4, 4, s_hrglass,      sdmd,     s2x2,     8,  0, 0, 1};
  426. static cm_thing oddmap2x2_dmd = {{6, 3, 2, 7}, {5, 0, 1, 4},            4, 4, s_hrglass,      sdmd,     s2x2,     8,  0, 1, 9};
  427. static cm_thing map2x2_1x4h = {{6, 7, 2, 3}, {0, 1, 4, 5},              4, 4, s_qtag,         s1x4,     s2x2,     8,  0, 0, 1};
  428. static cm_thing oddmap2x2_1x4h = {{6, 7, 2, 3}, {5, 0, 1, 4},           4, 4, s_bone,         s1x4,     s2x2,     8,  0, 1, 9};
  429. static cm_thing mapstar_1x4 =    {{1, 2, 5, 6}, {0, 3, 4, 7},           4, 4, s_3x1dmd,       s1x4,     s_star,   12, 0, 0, 9};
  430. static cm_thing oddmapstar_1x4 = {{1, 2, 5, 6}, {7, 0, 3, 4},           4, 4, s_3x1dmd,       s1x4,     s_star,   12, 0, 1, 9};
  431. static cm_thing mapstar_dmd ={{1, 3, 5, 7}, {0, 2, 4, 6},               4, 4, s_crosswave,    sdmd,     s_star,   8,  0, 0, 9};
  432. static cm_thing oddmapstar_dmd =  {{1, 3, 5, 7}, {6, 0, 2, 4},          4, 4, s_crosswave,    sdmd,     s_star,   8,  0, 1, 9};
  433. static cm_thing map2x2_1x4v = {{6, 7, 2, 3}, {0, 1, 4, 5},              4, 4, s_bone,         s1x4,     s2x2,     8,  0, 0, 0};
  434. static cm_thing oddmap2x2_1x4v = {{6, 7, 2, 3}, {5, 0, 1, 4},           4, 4, s_qtag,         s1x4,     s2x2,     8,  0, 1, 9};
  435. static cm_thing map2x2_2x2v = {{1, 2, 5, 6}, {0, 3, 4, 7},              4, 4, s2x4,           s2x2,     s2x2,     8,  0, 0, 0};
  436. static cm_thing oddmap2x2_2x2h = {{1, 2, 5, 6}, {7, 0, 3, 4},           4, 4, s2x4,           s2x2,     s2x2,     8,  0, 1, 9};
  437. static cm_thing oddmap2x2_2x2v = {{6, 1, 2, 5}, {0, 3, 4, 7},           4, 4, s2x4,           s2x2,     s2x2,     8,  1, 0, 9};
  438. static cm_thing map2x2_2x2h = {{6, 1, 2, 5}, {7, 0, 3, 4},              4, 4, s2x4,           s2x2,     s2x2,     8,  1, 1, 9};
  439. static cm_thing maplatgal = {{7, 0, 1, 3, 4, 5}, {6, 2},                6, 2, s_galaxy,       s_short6, s_1x2,    8,  1, 1, 0};
  440. static cm_thing oddmap1x4_dmd = {{7, 2, 3, 6}, {0, 1, 4, 5},            4, 4, s_3x1dmd,       sdmd,     s1x4,     12, 1, 0, 0};
  441. static cm_thing oddmap1x2_bone6 = {{5, 0, 3, 1, 4, 7}, {6, 2},          6, 2, s_hrglass,      s_bone6,  s_1x2,    8,  1, 0, 0};
  442. static cm_thing oddmap1x2_2x3 = {{5, 7, 0, 1, 3, 4}, {6, 2},            6, 2, s_qtag,         s_2x3,    s_1x2,    8,  1, 0, 0};
  443. static cm_thing oddmap1x2_short6 = {{5, 7, 0, 1, 3, 4}, {6, 2},         6, 2, s_rigger,       s_short6, s_1x2,    8,  1, 0, 0};
  444. static cm_thing oddmap2x3_1x2 = {{11, 5}, {9, 10, 0, 3, 4, 6},          2, 6, s3x4,           s_1x2,    s_2x3,    12, 0, 1, 0};
  445. static cm_thing oddmapshort6_1x2h = {{2, 6}, {3, 0, 1, 7, 4, 5},        2, 6, s_ptpd,         s_1x2,    s_short6, 8,  0, 1, 1};
  446. static cm_thing oddmapshort6_1x2v = {{7, 3}, {5, 6, 0, 1, 2, 4},        2, 6, s_qtag,         s_1x2,    s_short6, 8,  0, 1, 0};
  447. static cm_thing oddmap1x2_short6_rc = {{5, 6, 0, 1, 2, 4}, {7, 3},      6, 2, s_rigger,       s_short6, s_1x2,    8,  1, 0, 0};
  448. static cm_thing map2x4_2x2 = {{2, 3, 8, 9}, {0, 1, 4, 5, 6, 7, 10, 11}, 4, 8, s2x6,           s2x2,     s2x4,     12, 0, 0, 9};
  449. static cm_thing oddmap2x4_2x2 = {{9, 2, 3, 8},
  450.                                        {0, 1, 4, 5, 6, 7, 10, 11},      4, 8, s2x6,           s2x2,     s2x4,     12, 1, 0, 9};
  451. static cm_thing mapdmd_line = {{1, 2, 5, 6}, {0, 3, 4, 7},              4, 4, s_3x1dmd,       s1x4,     sdmd,     8,  0, 0, 0};
  452. static cm_thing map_s_dmd_line = {{1, 2, 5, 6}, {0, 3, 4, 7},           4, 4, s_wingedstar,   s1x4,     sdmd,     8,  0, 0, 0};
  453. static cm_thing map_12_dmd_line = {{1, 2, 4, 7, 8, 10},
  454.                                                {11, 0, 3, 5, 6, 9},     6, 6, s_wingedstar12, s_1x6,    s_short6, 12,  0, 1, 0};
  455.  
  456.  
  457. static cm_thing *concmap1x2_1x2[4]       = {&map1x2_1x2,          &oddmap1x2_1x2,       &map1x2_1x2,      &oddmap1x2_1x2};
  458. static cm_thing *concmapdmd_dmd[4]       = {&mapdmd_dmd,          0,                    &mapdmd_dmd,      0};
  459. static cm_thing *concmapdmd_1x4[4]       = {&mapdmd_1x4,          &oddmapdmd_1x4,       &mapdmd_1x4,      &oddmapdmd_1x4};
  460. static cm_thing *concmap_s_dmd_1x4[4]    = {&map_s_dmd_1x4,       &oddmap_s_dmd_1x4,    &map_s_dmd_1x4,   &oddmap_s_dmd_1x4};
  461. static cm_thing *concmap_cs_1x4_dmd[4]   = {&map_cs_1x4_dmd,      0,                    &map_cs_1x4_dmd,  0};
  462. static cm_thing *concmap_s_star_1x4[4]   = {&map_s_star_1x4,      &oddmap_s_star_1x4,   &map_s_star_1x4,  &oddmap_s_star_1x4};
  463. static cm_thing *concmap_s_short_1x6[4]  = {0,                    &oddmap_s_short_1x6,  0,                0};
  464. static cm_thing *concmapdmd_2x2[4]       = {&mapdmd_2x2h,         &mapdmd_2x2v,         &mapdmd_2x2h,     &mapdmd_2x2v};
  465. static cm_thing *concmap2x2_2x2[4]       = {&map2x2_2x2v,         &oddmap2x2_2x2v,      &map2x2_2x2h,     &oddmap2x2_2x2h};
  466. static cm_thing *concmap2x2_1x4[4]       = {&map2x2_1x4v,         &oddmap2x2_1x4v,      &map2x2_1x4h,     &oddmap2x2_1x4h};
  467. static cm_thing *concmap2x2_dmd[4]       = {0,                    &oddmap2x2_dmd,       &map2x2_dmd,      0};
  468. static cm_thing *concmapshort6_1x2[4]    = {&mapshort6_1x2v,      &oddmapshort6_1x2v,   &mapshort6_1x2h,  &oddmapshort6_1x2h};
  469. static cm_thing *concmap1x2_1x6[4]       = {&map1x2_1x6,          &oddmap1x2_1x6,       &map1x2_1x6,      &oddmap1x2_1x6};
  470. static cm_thing *concmap1x2_bone6[4]     = {&map1x2_bone6,        &oddmap1x2_bone6,     &map1x2_bone6,    &oddmap1x2_bone6};
  471. static cm_thing *concmap1x2_2x3[4]       = {&map1x2_2x3,          &oddmap1x2_2x3,       &map1x2_2x3,      &oddmap1x2_2x3};
  472. static cm_thing *concmap1x2_short6[4]    = {&map1x2_short6,       &oddmap1x2_short6,    &map1x2_short6,   &oddmap1x2_short6};
  473. static cm_thing *concmap2x4_2x2[4]       = {&map2x4_2x2,          &oddmap2x4_2x2,       &map2x4_2x2,      &oddmap2x4_2x2};
  474. static cm_thing *concmap1x4_2x2[4]       = {&map1x4_2x2,          &oddmap1x4_2x2,       &map1x4_2x2,      &oddmap1x4_2x2};
  475. static cm_thing *concmap1x4_star[4]      = {&map1x4_star,         &oddmap1x4_star,      &map1x4_star,     &oddmap1x4_star};
  476. static cm_thing *concmap1x4_dmd[4]       = {0,                    &oddmap1x4_dmd,       0,                &oddmap1x4_dmd};
  477. static cm_thing *concmap1x4_1x4[4]       = {&map1x4_1x4,          &oddmap1x4_1x4,       &map1x4_1x4,      &oddmap1x4_1x4};
  478. static cm_thing *concmapstar_2x2[4]      = {&mapstar_2x2,         0,                    &mapstar_2x2,     0};
  479. static cm_thing *concmapstar_1x4[4]      = {&mapstar_1x4,         &oddmapstar_1x4,      &mapstar_1x4,     &oddmapstar_1x4};
  480. static cm_thing *concmapstar_dmd[4]      = {&mapstar_dmd,         &oddmapstar_dmd,      &mapstar_dmd,     &oddmapstar_dmd};
  481. static cm_thing *concmap2x3_1x2[4]       = {&map2x3_1x2,          &oddmap2x3_1x2,       &map2x3_1x2,      &oddmap2x3_1x2};
  482. static cm_thing *concmap2x3_2x3[4]       = {&map2x3_2x3,          0,                    &map2x3_2x3,      0};
  483. static cm_thing *concmapbone6_1x2[4]     = {&mapbone6_1x2,        0,                    &mapbone6_1x2,    0};
  484. static cm_thing *concmap1x6_1x2[4]       = {&map1x6_1x2,          0,                    &map1x6_1x2,      0};
  485. static cm_thing *concmap1x4_1x4_rc[4]    = {&map1x4_1x4_rc,       0,                    &map1x4_1x4_rc,   0};
  486. static cm_thing *concmap2x2_dmd_rc[4]    = {&map2x2_dmd_rc,       0,                    &map2x2_dmd_rc,   0};
  487. static cm_thing *concmap2x2_1x4_rc[4]    = {&map2x2_1x4_rc,       &oddmap2x2_1x4_rc,    &map2x2_1x4_rc,   &oddmap2x2_1x4_rc};
  488.  
  489.  
  490.  
  491. /* This overwrites its "inners" and "outers argument setups. */
  492. extern void normalize_concentric(
  493.    calldef_schema synthesizer,
  494.    int center_arity,
  495.    setup inners[],
  496.    setup *outers,
  497.    int outer_elongation,
  498.    setup *result)
  499. {
  500.    /* If "outer_elongation" < 0, the outsides can't deduce their ending spots on
  501.       the basis of the starting formation.  In this case, it is an error unless
  502.       they go to some setup for which their elongation is obvious, like a 1x4. */
  503.  
  504.    int i, j, q, rot;
  505.    cm_thing **map_ptr;
  506.    cm_thing *lmap_ptr;
  507.  
  508.    clear_people(result);
  509.  
  510.    /* If a call was being done "piecewise" or "random", we demand that both
  511.       calls run out of parts at the same time, and, when that happens, we
  512.       report it to the higher level in the recursion. */
  513.  
  514.    if ((inners[0].setupflags ^ outers->setupflags) & RESULTFLAG__DID_LAST_PART)
  515.       fail("Centers and ends parts must use the same number of fractions.");
  516.  
  517.    result->setupflags = inners[0].setupflags | outers->setupflags;
  518.  
  519.    if (inners[0].kind == nothing && outers->kind == nothing) {
  520.       result->kind = nothing;
  521.       return;
  522.    }
  523.  
  524.    compute_rotation_again:
  525.  
  526.    i = (inners[0].rotation - outers->rotation) & 3;
  527.  
  528.    map_ptr = 0;
  529.  
  530.    if (center_arity != 1) {
  531.       if (synthesizer != schema_conc_star12 || outers->kind != s1x4 || inners[0].kind != s_star || inners[1].kind != s_star)
  532.          fail("Can't do this with 12 matrix stars.");
  533.  
  534.       if (i&1)
  535.          lmap_ptr = &map_spec_star12v;
  536.       else
  537.          lmap_ptr = &map_spec_star12;
  538.  
  539.       goto gotit;
  540.    }
  541.  
  542.    if (synthesizer == schema_rev_checkpoint) {
  543.       /* Fix up nonexistent centers or ends, in a rather inept way. */
  544.       if (inners[0].kind == nothing) {
  545.          inners[0].kind = outers->kind;
  546.          inners[0].rotation = outers->rotation;
  547.          inners[0].setupflags = outers->setupflags;
  548.          clear_people(&inners[0]);
  549.          i = 0;
  550.       }
  551.       else if (outers->kind == nothing) {
  552.          outers->kind = inners[0].kind;
  553.          outers->rotation = inners[0].rotation;
  554.          outers->setupflags = inners[0].setupflags;
  555.          clear_people(outers);
  556.          i = 0;
  557.       }
  558.  
  559.       switch (outers->kind) {
  560.          case s2x2:
  561.             switch (inners[0].kind) {
  562.                case s1x4: map_ptr = concmap2x2_1x4_rc; break;
  563.                case sdmd: map_ptr = concmap2x2_dmd_rc; break;
  564.             }
  565.             break;
  566.          case s1x4:
  567.             switch (inners[0].kind) {
  568.                case s1x4: map_ptr = concmap1x4_1x4_rc; break;
  569.                case sdmd:
  570.                   /* This is a diamond inside a 1x4, oriented the bad way.
  571.                      Leave it as a concentric setup. */
  572.                   if (!(i&1)) {
  573.                      result->inner.skind = inners[0].kind;
  574.                      result->inner.srotation = inners[0].rotation;
  575.                      result->outer.skind = outers->kind;
  576.                      result->outer.srotation = outers->rotation;
  577.                      result->outer_elongation = 0;
  578.                      result->kind = s_normal_concentric;
  579.                      if (i == 0) {
  580.                         install_person(result, 0, outers, 1);
  581.                         install_person(result, 2, outers, 3);
  582.                         install_person(result, 1, &inners[0], 1);
  583.                         install_person(result, 3, &inners[0], 3);
  584.                         install_person(result, 12, &inners[0], 0);
  585.                         install_person(result, 14, &inners[0], 2);
  586.                         install_person(result, 13, outers, 0);
  587.                         install_person(result, 15, outers, 2);
  588.                      }
  589.                      else
  590.                         fail("Sorry, code is broken at line 581 of sdconc.c.");
  591.  
  592.                      canonicalize_rotation(result);
  593.                      return;
  594.                   }
  595.             }
  596.             break;
  597.       }
  598.    }
  599.    else if (synthesizer == schema_ckpt_star) {
  600.       /* There are a few cases of centers or ends being phantoms, in which
  601.          we nevertheless know what to do, since we know that the setup should
  602.          be some kind of "winged star". */
  603.       if (inners[0].kind == nothing && outers->kind == s1x4) {
  604.          inners[0].kind = s_star;
  605.          inners[0].rotation = 0;
  606.          inners[0].setupflags = outers->setupflags;
  607.          clear_people(&inners[0]);
  608.          goto compute_rotation_again;
  609.       }
  610.       else if (inners[0].kind == sdmd && outers->kind == nothing) {
  611.          /* The test case for this is: RWV:intlkphanbox relay top;splitphanbox flip reaction. */
  612.          outers->kind = s1x4;
  613.          outers->rotation = inners[0].rotation;
  614.          outers->setupflags = inners[0].setupflags;
  615.          clear_people(outers);
  616.          goto compute_rotation_again;
  617.       }
  618.  
  619.       switch (outers->kind) {
  620.          case s1x4:
  621.             switch (inners[0].kind) {
  622.                case sdmd: map_ptr = concmap_cs_1x4_dmd; break;
  623.             }
  624.             break;
  625.       }
  626.    }
  627.    else if (synthesizer == schema_conc_star) {
  628.       /* There are a few cases of centers or ends being phantoms, in which
  629.          we nevertheless know what to do, since we know that the setup should
  630.          be some kind of "winged star". */
  631.       if (outers->kind == nothing && inners[0].kind == s1x4) {
  632.          outers->kind = s_star;
  633.          outers->rotation = 0;
  634.          outers->setupflags = inners[0].setupflags;
  635.          clear_people(outers);
  636.          goto compute_rotation_again;
  637.       }
  638.       else if (outers->kind == nothing && inners[0].kind == s_star) {
  639.          outers->kind = s1x4;
  640.          outers->rotation = outer_elongation;
  641.          outers->setupflags = inners[0].setupflags;
  642.          clear_people(outers);
  643.          goto compute_rotation_again;
  644.       }
  645.       else if (outers->kind == s1x4 && inners[0].kind == nothing) {
  646.          inners[0].kind = s_star;
  647.          inners[0].rotation = 0;
  648.          inners[0].setupflags = outers->setupflags;
  649.          clear_people(&inners[0]);
  650.          goto compute_rotation_again;
  651.       }
  652.  
  653.       switch (outers->kind) {
  654.          case sdmd:
  655.             switch (inners[0].kind) {
  656.                case s1x4: map_ptr = concmap_s_dmd_1x4; break;
  657.             }
  658.             break;
  659.          case s_star:
  660.             switch (inners[0].kind) {
  661.                case s1x4: map_ptr = concmap_s_star_1x4; break;
  662.             }
  663.             break;
  664.          case s1x4:
  665.             switch (inners[0].kind) {
  666.                case s_star: map_ptr = concmap1x4_star; break;
  667.                case s1x4:
  668.                   /* In certain phantom cases, what should have been a diamond
  669.                      around the outside, resulting from a 1/2 circulate, will be
  670.                      a line with the two centers missing, since the basic_move
  671.                      routine gives preference to a line when it is ambiguous.
  672.                      If this happens, we have to turn it back into a diamond. */
  673.                   if (!(outers->people[1].id1 | outers->people[3].id1)) {
  674.                      outers->kind = sdmd;  /* That's all that it takes to fix it. */
  675.                      goto compute_rotation_again;
  676.                   }
  677.                   /* Or the two ends missing. */
  678.                   else if (!(outers->people[0].id1 | outers->people[2].id1)) {
  679.                      outers->kind = sdmd;
  680.                      outers->rotation = (outers->rotation-1) & 3;
  681.                      (void) copy_rot(outers, 1, outers, 1, 011);
  682.                      (void) copy_rot(outers, 3, outers, 3, 011);
  683.                      canonicalize_rotation(outers);
  684.                      goto compute_rotation_again;
  685.                   }
  686.             }
  687.             break;
  688.       }
  689.    }
  690.    else if (synthesizer == schema_conc_star12) {
  691.       switch (outers->kind) {
  692.          case s_short6:
  693.             switch (inners[0].kind) {
  694.                case s_1x6: map_ptr = concmap_s_short_1x6; break;
  695.             }
  696.             break;
  697.       }
  698.    }
  699.    else {
  700.       /* Fix up nonexistent centers or ends, in a rather inept way. */
  701.       if (inners[0].kind == nothing) {
  702.          inners[0].kind = outers->kind;
  703.          inners[0].rotation = outers->rotation;
  704.          inners[0].setupflags = outers->setupflags;
  705.          clear_people(&inners[0]);
  706.          i = 0;
  707.       }
  708.       else if (outers->kind == nothing) {
  709.          outers->kind = inners[0].kind;
  710.          outers->rotation = inners[0].rotation;
  711.          outers->setupflags = inners[0].setupflags;
  712.          clear_people(outers);
  713.          i = 0;
  714.       }
  715.  
  716.       /* Nonexistent center or ends have been taken care of.  Now figure out how to put
  717.          the setups together. */
  718.  
  719.       switch (outers->kind) {
  720.          case s_1x6:
  721.             switch (inners[0].kind) {
  722.                case s_1x2: map_ptr = concmap1x6_1x2; break;
  723.             }
  724.             break;
  725.          case s_bone6:
  726.             switch (inners[0].kind) {
  727.                case s_1x2: map_ptr = concmapbone6_1x2; break;
  728.             }
  729.             break;
  730.          case s_2x3:
  731.             switch (inners[0].kind) {
  732.                case s_1x2: map_ptr = concmap2x3_1x2; break;
  733.                case s_2x3: map_ptr = concmap2x3_2x3; break;
  734.             }
  735.             break;
  736.          case s2x4:
  737.             switch (inners[0].kind) {
  738.                case s2x2: map_ptr = concmap2x4_2x2; break;
  739.             }
  740.             break;
  741.          case s1x4:
  742.             switch (inners[0].kind) {
  743.                case s1x4: map_ptr = concmap1x4_1x4; break;
  744.                case sdmd: map_ptr = concmap1x4_dmd; break;
  745.                case s_star: map_ptr = concmap1x4_star; break;
  746.                case s2x2: map_ptr = concmap1x4_2x2; break;
  747.             }
  748.             break;
  749.          case s_1x2:
  750.             switch (inners[0].kind) {
  751.                case s_1x2:    map_ptr = concmap1x2_1x2; break;
  752.                case s_2x3:    map_ptr = concmap1x2_2x3; break;
  753.                case s_bone6 : map_ptr = concmap1x2_bone6; break;
  754.                case s_short6: map_ptr = concmap1x2_short6; break;
  755.                case s_1x6:    map_ptr = concmap1x2_1x6; break;
  756.             }
  757.             break;
  758.          case s_short6:
  759.             switch (inners[0].kind) {
  760.                case s_1x2: map_ptr = concmapshort6_1x2; break;
  761.             }
  762.             break;
  763.          case s2x2:
  764.             switch (inners[0].kind) {
  765.                case s2x2: map_ptr = concmap2x2_2x2; break;
  766.                case s1x4: map_ptr = concmap2x2_1x4; break;
  767.                case sdmd: map_ptr = concmap2x2_dmd; break;
  768.             }
  769.             break;
  770.          case sdmd:
  771.             switch (inners[0].kind) {
  772.                case sdmd: map_ptr = concmapdmd_dmd; break;
  773.                case s1x4: map_ptr = concmapdmd_1x4; break;
  774.                case s2x2: map_ptr = concmapdmd_2x2; break;
  775.             }
  776.             break;
  777.          case s_star:
  778.             switch (inners[0].kind) {
  779.                case sdmd: map_ptr = concmapstar_dmd; break;
  780.                case s1x4: map_ptr = concmapstar_1x4; break;
  781.                case s2x2: map_ptr = concmapstar_2x2; break;
  782.             }
  783.             break;
  784.       }
  785.    }
  786.  
  787.    if (!map_ptr) goto anomalize_it;
  788.  
  789.    if (outer_elongation < 0) {
  790.       /* We need to find out whether it would have made a difference
  791.          when picking out the map. */
  792.  
  793.       if (map_ptr[(i&1)] != map_ptr[(i&1) + 2]) goto elongation_loss;
  794.    }
  795.  
  796.    lmap_ptr = map_ptr[(i&1) + (((outer_elongation ^ outers->rotation) & 1) << 1)];
  797.  
  798. gotit:
  799.  
  800.    if (!lmap_ptr) goto anomalize_it;
  801.  
  802.    result->kind = lmap_ptr->bigsetup;
  803.    result->rotation = outers->rotation + lmap_ptr->outer_rot;
  804.  
  805.    rot = ((-lmap_ptr->outer_rot) & 3) * 011;
  806.    for (j=0; j<lmap_ptr->outlimit; j++)
  807.       (void) copy_rot(result, lmap_ptr->mapout[j], outers, j, rot);
  808.  
  809.    /* Find out whether inners need to be flipped around. */
  810.    q = i + lmap_ptr->inner_rot - lmap_ptr->outer_rot;
  811.  
  812.    if (q & 1)
  813.       fail("Sorry, there is a bug in normalize_concentric.");
  814.  
  815.    if (q & 2) {
  816.       inners[0].rotation += 2;
  817.       canonicalize_rotation(&inners[0]);
  818.    }
  819.  
  820.    rot = ((-lmap_ptr->inner_rot) & 3) * 011;
  821.    for (j=0; j<lmap_ptr->inlimit; j++)
  822.       (void) copy_rot(result, lmap_ptr->mapin[j], &inners[0], j, rot);
  823.  
  824.    if (lmap_ptr == &map_spec_star12) {
  825.       if (q & 2) {
  826.          inners[1].rotation += 2;
  827.          canonicalize_rotation(&inners[1]);
  828.       }
  829.       (void) copy_rot(result, 10, &inners[1], 0, rot);
  830.       (void) copy_rot(result, 5,  &inners[1], 1, rot);
  831.       (void) copy_rot(result, 8,  &inners[1], 2, rot);
  832.       (void) copy_rot(result, 9,  &inners[1], 3, rot);
  833.    }
  834.    else if (lmap_ptr == &map_spec_star12v) {
  835.       if (q & 2) {
  836.          inners[1].rotation += 2;
  837.          canonicalize_rotation(&inners[1]);
  838.       }
  839.       (void) copy_rot(result, 9,  &inners[1], 0, rot);
  840.       (void) copy_rot(result, 10, &inners[1], 1, rot);
  841.       (void) copy_rot(result, 5,  &inners[1], 2, rot);
  842.       (void) copy_rot(result, 8,  &inners[1], 3, rot);
  843.    }
  844.  
  845.    canonicalize_rotation(result);
  846.    return;
  847.  
  848.    anomalize_it:            /* Failed, just leave it as it is. */
  849.  
  850.    switch (synthesizer) {
  851.       case schema_rev_checkpoint:
  852.          fail("Sorry, can't figure out this reverse checkpoint result.");
  853.       case schema_single_concentric:
  854.       case schema_single_cross_concentric:
  855.          fail("Can't figure out this single concentric result.");
  856.       case schema_conc_star:
  857.       case schema_conc_star12:
  858.          fail("Can't figure out this concentric result.");
  859.    }
  860.  
  861.    if (outer_elongation < 0) goto elongation_loss;
  862.  
  863.    result->kind = s_normal_concentric;
  864.    result->inner.skind = inners[0].kind;
  865.    result->inner.srotation = inners[0].rotation;
  866.    result->outer.skind = outers->kind;
  867.    result->outer.srotation = outers->rotation;
  868.    result->outer_elongation = outer_elongation ^ outers->rotation;
  869.    for (j=0; j<12; j++) {
  870.       (void) copy_person(result, j, &inners[0], j);
  871.       (void) copy_person(result, j+12, outers, j);
  872.    }
  873.    canonicalize_rotation(result);
  874.    return;
  875.  
  876.    elongation_loss:
  877.    fail("Ends can't figure out what spots to finish on.");
  878. }
  879.  
  880.  
  881.  
  882. /* This "normalizes" the setup, checking whether a 3x4 is actually occupied only in the
  883.    spots of a qtag, and reducing it if so. */
  884.  
  885. static void normalize_3x4(setup *stuff)
  886.  
  887. {
  888.    if ((!stuff->people[0].id1) && (!stuff->people[3].id1) && (!stuff->people[6].id1) && (!stuff->people[9].id1)) {
  889.       stuff->kind = s_qtag;
  890.       (void) copy_person(stuff, 0, stuff, 1);         /* careful -- order is important */
  891.       (void) copy_person(stuff, 1, stuff, 2);
  892.       (void) copy_person(stuff, 2, stuff, 4);
  893.       (void) copy_person(stuff, 3, stuff, 5);
  894.       (void) copy_person(stuff, 4, stuff, 7);
  895.       (void) copy_person(stuff, 5, stuff, 8);
  896.       (void) copy_person(stuff, 6, stuff, 10);
  897.       (void) copy_person(stuff, 7, stuff, 11);
  898.    }
  899. }
  900.  
  901.  
  902. /* The "level" argument tells how hard we work to remove the outside phantoms.
  903.    When merging the results of "on your own" or "own the so-and-so",
  904.    we set level=normalize_before_merge to work very hard at stripping away
  905.    outside phantoms, so that we can see more readily how to put things together.
  906.    When preparing for an isolated call, we work at it a little, so
  907.    level=normalize_before_isolated_call.   For normal usage, level=simple_normalize. */
  908. extern void normalize_setup(setup *ss, normalize_level level)
  909. {
  910.    setup temp;
  911.  
  912.    /* Normalize setup by removing outboard phantoms. */
  913.    
  914.    if (ss->kind == s_bigblob)
  915.       normalize_blob(ss);           /* This might leave a 4x6, which might be reduced further. */
  916.  
  917.    if (ss->kind == s4x6)
  918.       normalize_4x6(ss);            /* This might leave a 4x4 or 2x6, which might be reduced further. */
  919.  
  920.    if (ss->kind == s4x4)
  921.       normalize_4x4(ss);
  922.    else if (ss->kind == s_3dmd)
  923.       normalize_3dmd(ss);
  924.    else if (ss->kind == s_4dmd)
  925.       normalize_4dmd(ss);
  926.    else if (ss->kind == s_c1phan)
  927.       normalize_c1_phan(ss);
  928.    else if (ss->kind == s3x4)
  929.       normalize_3x4(ss);
  930.    else if (ss->kind == s2x8) {
  931.       temp = *ss;
  932.       normalize_2x8(&temp, ss);     /* This might leave a 2x6, which could then be reduced to 2x4, below. */
  933.    }
  934.    
  935.    if (ss->kind == s2x6)
  936.       normalize_2x6(ss);
  937.  
  938.    /* If preparing for a "so-and-so only do whatever", we remove outboard phantoms
  939.       more aggressively.  For example, if we are selecting just the center line of
  940.       a quarter tag, we reduce the setup all the way down to a line.  Normally we
  941.       wouldn't do this, lest we lose phantoms when gluing setups together. */
  942.  
  943.    if (level >= normalize_before_merge) {
  944.       /* This reduction is necessary to make "ends only rotate 1/4" work from a DPT, yielding a rigger. */
  945.       if ((ss->kind == s2x4) && (!(ss->people[0].id1 | ss->people[3].id1 | ss->people[4].id1 | ss->people[7].id1))) {
  946.          ss->kind = s2x2;
  947.          (void) copy_person(ss, 0, ss, 1);
  948.          (void) copy_person(ss, 1, ss, 2);
  949.          (void) copy_person(ss, 2, ss, 5);
  950.          (void) copy_person(ss, 3, ss, 6);
  951.       }
  952.       else if ((ss->kind == s1x8) && (!(ss->people[0].id1 | ss->people[1].id1 | ss->people[4].id1 | ss->people[5].id1))) {
  953.          ss->kind = s1x4;
  954.          (void) copy_person(ss, 0, ss, 3);
  955.          (void) copy_person(ss, 1, ss, 2);
  956.          (void) copy_person(ss, 2, ss, 7);
  957.          (void) copy_person(ss, 3, ss, 6);
  958.       }
  959.    }
  960.  
  961.    if (level >= normalize_before_isolated_call) {
  962.       if (ss->kind == s_qtag) {
  963.          if (!(ss->people[0].id1 | ss->people[1].id1 | ss->people[4].id1 | ss->people[5].id1)) {
  964.             ss->kind = s1x4;
  965.             (void) copy_person(ss, 0, ss, 6);
  966.             (void) copy_person(ss, 1, ss, 7);
  967.          }
  968.          if (!(ss->people[2].id1 | ss->people[3].id1 | ss->people[6].id1 | ss->people[7].id1)) {
  969.             /* We do NOT compress to a 2x2 -- doing so might permit people to
  970.                work with each other across the set when they shouldn't, as in
  971.                "heads pass the ocean; heads recycle while the sides star thru". */
  972.             ss->kind = s2x4;
  973.             ss->rotation++;
  974.             (void) copy_rot(ss, 7, ss, 0, 033);         /* careful -- order is important */
  975.             (void) copy_rot(ss, 3, ss, 4, 033);
  976.             (void) copy_rot(ss, 0, ss, 1, 033);
  977.             (void) copy_rot(ss, 4, ss, 5, 033);
  978.             clear_person(ss, 1);
  979.             clear_person(ss, 5);
  980.             canonicalize_rotation(ss);
  981.          }
  982.       }
  983.    }
  984. }
  985.  
  986.  
  987. /* BEWARE!!  This list is keyed to the definition of "setup_kind" in database.h . */
  988. /* The horizontal structure is keyed to the enumeration "analyzer_kind" :
  989.    normal      checkpt                   2x6                 6x2             star12             single       vertical6          lateral6     diamond_line */
  990.  
  991. static cm_thing *bigconctab[][9] = {
  992.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* nothing */
  993.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x1 */
  994.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x2 */
  995.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x3 */
  996.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x2 */
  997.    {0,              0,                    0,                  0,                 0,                &oddmap1x2_1x2, 0,                0,          0},               /* sdmd */
  998.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_star */
  999.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_trngl */
  1000.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_bone6 */
  1001.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_short6 */
  1002.    {&map2x2_1x4h,   0,                    &oddmapshort6_1x2v, &oddmap1x2_2x3,    0,                0,              0,                0,          0},               /* s_qtag */
  1003.    {&map2x2_1x4v,   &map1x2_bone6_rc,     &mapbone6_1x2,      0,                 0,                0,              0,                0,          0},               /* s_bone */
  1004.    {&map1x4_2x2,    &oddmap1x2_short6_rc, 0,                  &oddmap1x2_short6, 0,                0,              0,                0,          0},               /* s_rigger */
  1005.    {0,              &map2x2_dmd_rc,       &mapshort6_1x2h,    &map1x2_2x3,       0,                0,              0,                0,          0},               /* s_spindle */
  1006.    {&map2x2_dmd,    0,                    &mapshort6_1x2v,    0,                 0,                0,              &oddmap1x2_bone6, 0,          0},               /* s_hrglass */
  1007.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_hyperglass */
  1008.    {&oddmap1x4_1x4, 0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_crosswave */
  1009.    {0,              0,                    0,                  0,                 0,                &map1x2_1x2,    0,                0,          0},               /* s1x4 */
  1010.    {&map1x4_1x4,    &map1x4_1x4_rc,       &map1x6_1x2,        &map1x2_1x6,       0,                0,              0,                0,          0},               /* s1x8 */
  1011.    {&map2x2_2x2v,   0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x4 */
  1012.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_2x3 */
  1013.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x6 */
  1014.    {0,              0,                    &oddmap2x3_1x2,     0,                 &map2x3_2x3,      0,              0,                0,          0},               /* s3x4 */
  1015.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x6 */
  1016.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x8 */
  1017.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s4x4 */
  1018.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_c1phan */
  1019.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_bigblob */
  1020.    {0,              &map2x2_1x4_rc,       &oddmapshort6_1x2h, &map1x2_bone6,     0,                0,              0,                0,          0},               /* s_ptpd */
  1021.    {&oddmap1x4_dmd, 0,                    0,                  &oddmap1x2_1x6,    0,                0,              0,                0,          &mapdmd_line},    /* s_3x1dmd */
  1022.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_3dmd */
  1023.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_4dmd */
  1024.    {&map1x4_star,   0,                    0,                  0,                 0,                0,              0,                0,          &map_s_dmd_line}, /* s_wingedstar */
  1025.    {0,              0,                    0,                  0,                 &map_spec_star12, 0,              0,                0,          &map_12_dmd_line},/* s_wingedstar12 */
  1026.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_wingedstar16 */
  1027.    {&mapstar_2x2,   0,                    0,                  0,                 0,                0,              &map1x2_short6,   &maplatgal, 0},               /* s_galaxy */
  1028.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s4x6 */
  1029.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_thar */
  1030.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0}};              /* s_normal_concentric */
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036. /* This is keyed to the enumeration "analyzer_kind". */
  1037. static char *conc_error_messages[] = {
  1038.    "Can't find centers and ends in this formation.",                   /* analyzer_NORMAL */
  1039.    "Can't find checkpoint people in this formation.",                  /* analyzer_CHECKPT */
  1040.    "Can't find 2 centers and 6 ends in this formation.",               /* analyzer_2X6 */
  1041.    "Can't find 6 centers and 2 ends in this formation.",               /* analyzer_6X2 */
  1042.    "Can't find 12 matrix centers and ends in this formation.",         /* analyzer_STAR12 */
  1043.    "Can't find single concentric centers and ends in this formation.", /* analyzer_SINGLE */
  1044.    "Wrong formation.",                                                 /* analyzer_VERTICAL6 */
  1045.    "Wrong formation.",                                                 /* analyzer_LATERAL6 */
  1046.    "Can't find center line and outer diamond."                         /* analyzer_DIAMOND_LINE */
  1047. };
  1048.  
  1049.  
  1050.  
  1051.  
  1052. /* This sets "outer_elongation" to the absolute elongation of the
  1053.    outsides.  If the outsides are in a 2x2, this, along with individual
  1054.    facing directions, will permit enforcement of the "lines-to-lines/
  1055.    columns-to-columns" rule.  Otherwise, this will permit enforcement
  1056.    of the Hodson checkpoint rule.
  1057.    
  1058.    There are a few cases in which this result may seem wrong:
  1059.       (1) If we have triple diamonds with points in only the center
  1060.          diamond (that is, a line of 6 with some points hanging off
  1061.          the center 2), and we ask for the center 6/outer 2, the
  1062.          lonesome points become the ends, and "outer_elongation"
  1063.          reflects their elongation, even though the line of 6 is longer.
  1064.          This doesn't seem to affect any checkpoint or concentric cases.
  1065.          Perhaps the phrases "center 6" and "outer 2" aren't really
  1066.          correct here.
  1067.       (2) If we have a quarter tag, and we ask for the center 6/outer 2,
  1068.          the center 6 are, of course, a 2x3, and the ends of the line
  1069.          are the outer 2.  We set "outer_elongation" to reflect
  1070.          the elongation of the outer 2, which may not be what people
  1071.          would think.  Once again, this does not arise in any actual
  1072.          checkpoint or concentric case.
  1073.       (3) If we have an "H", and we ask for the center 2/outer 6, the
  1074.          outer 6 are the 2x3, and "outer_elongation" will show
  1075.          their elongation, even though that is not the elongation of
  1076.          the 3x4 matrix.  Once again, this does not arise in any actual
  1077.          checkpoint or concentric case. */
  1078.  
  1079. static void concentrify(
  1080.    setup *ss,
  1081.    calldef_schema analyzer,
  1082.    setup inners[],
  1083.    setup *outers,
  1084.    int *center_arity,
  1085.    int *outer_elongation,    /* Set to elongation of original outers. */
  1086.    int *xconc_elongation)    /* If cross concentric, set to elongation of original ends. */
  1087.  
  1088. {
  1089.    int i, rot, analyzer_index;
  1090.    cm_thing *lmap_ptr;   
  1091.  
  1092.    clear_people(outers);
  1093.    clear_people(&inners[0]);
  1094.  
  1095.    outers->setupflags = ss->setupflags;
  1096.    inners[0].setupflags = ss->setupflags;
  1097.  
  1098.    *center_arity = 1;
  1099.  
  1100.    /* First, translate the analyzer into a form that encodes only what we need to know. */
  1101.  
  1102.    switch (analyzer) {
  1103.       case schema_lateral_6:
  1104.          analyzer_index = analyzer_LATERAL6; break;
  1105.       case schema_vertical_6:
  1106.          analyzer_index = analyzer_VERTICAL6; break;
  1107.       case schema_checkpoint:
  1108.       case schema_ckpt_star:
  1109.          analyzer_index = analyzer_CHECKPT; break;
  1110.       case schema_single_concentric:
  1111.       case schema_single_cross_concentric:
  1112.          analyzer_index = analyzer_SINGLE; break;
  1113.       case schema_conc_star12:
  1114.          analyzer_index = analyzer_STAR12; break;
  1115.       case schema_concentric_diamond_line:
  1116.          analyzer_index = analyzer_DIAMOND_LINE; break;
  1117.       case schema_concentric_6_2:
  1118.          analyzer_index = analyzer_6X2; break;
  1119.       case schema_concentric_2_6:
  1120.          if (ss->kind == s3x4 && ((ss->people[1].id1 | ss->people[2].id1 | ss->people[7].id1 | ss->people[8].id1) ||
  1121.                      (!(ss->people[0].id1 & ss->people[3].id1 & ss->people[4].id1 & ss->people[5].id1 &
  1122.                      ss->people[6].id1 & ss->people[9].id1 & ss->people[10].id1 & ss->people[11].id1))))
  1123.             fail("Can't find centers and ends in this formation.");
  1124.          analyzer_index = analyzer_2X6;
  1125.          break;
  1126.       case schema_rev_checkpoint:
  1127.       case schema_concentric:
  1128.       case schema_conc_star:
  1129.       case schema_cross_concentric:
  1130.          analyzer_index = analyzer_NORMAL; break;
  1131.       case schema_maybe_single_concentric:
  1132.          fail("Can't figure out whether concentric is single -- this shouldn't happen.");
  1133.       case schema_maybe_matrix_conc_star:
  1134.          fail("Can't figure out whether concentric is 12 or 16 matrix -- this shouldn't happen.");
  1135.       default:
  1136.          fail("Don't understand this concentricity type???.");
  1137.    }
  1138.  
  1139.    /* Next, deal with the "normal_concentric" special case.
  1140.       We need to be careful here.  The setup was not able to be normalized, but
  1141.       we are being asked to pick out centers and ends.  There are very few
  1142.       non-normal concentric setups for which we can do that correctly.  For example,
  1143.       if we have concentric diamonds whose points are along different axes from each
  1144.       other, who are the 4 centers of the total setup?  (If the axes of the diamonds
  1145.       had been consistent, the setup would have been normalized to crossed lines,
  1146.       and we wouldn't be here.)
  1147.       If we don't take action here and the setup is normal_concentric, an error will
  1148.       be raised, since the "bigconctab" entries are zero. */
  1149.  
  1150.    if (ss->kind == s_normal_concentric) {
  1151.       outers->rotation = ss->outer.srotation;
  1152.       inners[0].rotation = ss->outer.srotation;
  1153.  
  1154.       switch (analyzer_index) {
  1155.          case analyzer_DIAMOND_LINE:
  1156.             if (ss->inner.skind == sdmd && ss->inner.srotation == ss->outer.srotation) {
  1157.                inners[0].kind = s1x4;
  1158.                outers->kind = sdmd;
  1159.                (void) copy_person(&inners[0], 0, ss, 13);
  1160.                (void) copy_person(&inners[0], 1, ss, 0);
  1161.                (void) copy_person(&inners[0], 2, ss, 15);
  1162.                (void) copy_person(&inners[0], 3, ss, 2);
  1163.                (void) copy_person(outers, 0, ss, 12);
  1164.                (void) copy_person(outers, 1, ss, 1);
  1165.                (void) copy_person(outers, 2, ss, 14);
  1166.                (void) copy_person(outers, 3, ss, 3);
  1167.                if (ss->outer.skind == s1x4) {
  1168.                   *outer_elongation = ss->outer.srotation & 1;
  1169.                   goto finish;
  1170.                }
  1171.             }
  1172.             break;
  1173.          case analyzer_NORMAL:
  1174.             if (ss->inner.skind == sdmd && ss->inner.srotation == ss->outer.srotation) {
  1175.                inners[0].kind = sdmd;
  1176.                outers->kind = ss->outer.skind;
  1177.                for (i=0; i<4; i++) {
  1178.                   (void) copy_person(&inners[0], i, ss, i);
  1179.                   (void) copy_person(outers, i, ss, i+12);
  1180.                }
  1181.  
  1182.                /* We allow a diamond inside a box with wrong elongation (if elongation were good, it would be an hourglass.) */
  1183.                if (ss->outer.skind == s2x2) {
  1184.                   *outer_elongation = (ss->outer.srotation ^ ss->outer_elongation) & 1;
  1185.                   goto finish;
  1186.                }
  1187.                /* And a diamond inside a line with wrong elongation (if elongation were good, it would be a 3x1 diamond.) */
  1188.                if (ss->outer.skind == s1x4) {
  1189.                   *outer_elongation = ss->outer.srotation & 1;
  1190.                   goto finish;
  1191.                }
  1192.             }
  1193.             else if (ss->inner.skind == s_1x2 && ss->outer.skind == s_1x6 && ss->inner.srotation != ss->outer.srotation) {
  1194.                inners[0].kind = sdmd;
  1195.                outers->kind = s1x4;
  1196.  
  1197.                if ((ss->inner.srotation - ss->outer.srotation) & 2) {
  1198.                   (void) copy_rot(&inners[0], 1, ss, 1, 033);
  1199.                   (void) copy_rot(&inners[0], 3, ss, 0, 033);
  1200.                }
  1201.                else {
  1202.                   (void) copy_rot(&inners[0], 1, ss, 0, 011);
  1203.                   (void) copy_rot(&inners[0], 3, ss, 1, 011);
  1204.                }
  1205.  
  1206.                (void) copy_person(&inners[0], 0, ss, 14);
  1207.                (void) copy_person(&inners[0], 2, ss, 17);
  1208.                (void) copy_person(outers, 0, ss, 12);
  1209.                (void) copy_person(outers, 1, ss, 13);
  1210.                (void) copy_person(outers, 2, ss, 15);
  1211.                (void) copy_person(outers, 3, ss, 16);
  1212.  
  1213.                goto finish;
  1214.             }
  1215.             break;
  1216.       }
  1217.    }
  1218.  
  1219.    /* Next, do the 3x4 -> qtag fudging.  Don't ask permission, just do it. **** maybe that isn't right for Z calls. */
  1220.  
  1221.    if (analyzer_index == analyzer_NORMAL && ss->kind == s3x4) {
  1222.       inners[0].kind = s1x4;
  1223.       inners[0].rotation = ss->rotation;
  1224.       outers->kind = s2x2;
  1225.       outers->rotation = ss->rotation;
  1226.       *outer_elongation = (outers->rotation^1) & 1;
  1227.       (void) copy_person(&inners[0], 0, ss, 10);
  1228.       (void) copy_person(&inners[0], 1, ss, 11);
  1229.       (void) copy_person(&inners[0], 2, ss, 4);
  1230.       (void) copy_person(&inners[0], 3, ss, 5);
  1231.  
  1232.       if (!ss->people[0].id1 && ss->people[1].id1)
  1233.          (void) copy_person(outers, 0, ss, 1);
  1234.       else if (!ss->people[1].id1 && !ss->people[0].id1)
  1235.          (void) copy_person(outers, 0, ss, 0);
  1236.       else fail("Can't find centers and ends in this formation.");
  1237.  
  1238.       if (!ss->people[2].id1 && ss->people[3].id1)
  1239.          (void) copy_person(outers, 1, ss, 3);
  1240.       else if (!ss->people[3].id1 && ss->people[2].id1)
  1241.          (void) copy_person(outers, 1, ss, 2);
  1242.       else fail("Can't find centers and ends in this formation.");
  1243.  
  1244.       if (!ss->people[6].id1 && ss->people[7].id1)
  1245.          (void) copy_person(outers, 2, ss, 7);
  1246.       else if (!ss->people[7].id1 && ss->people[6].id1)
  1247.          (void) copy_person(outers, 2, ss, 6);
  1248.       else fail("Can't find centers and ends in this formation.");
  1249.  
  1250.       if (!ss->people[8].id1 && ss->people[9].id1)
  1251.          (void) copy_person(outers, 3, ss, 9);
  1252.       else if (!ss->people[9].id1 && ss->people[8].id1)
  1253.          (void) copy_person(outers, 3, ss, 8);
  1254.       else fail("Can't find centers and ends in this formation.");
  1255.       goto finish;
  1256.    }
  1257.  
  1258.    lmap_ptr = bigconctab[ss->kind][analyzer_index];
  1259.    if (!lmap_ptr) fail(conc_error_messages[analyzer_index]);
  1260.  
  1261.    inners[0].kind = lmap_ptr->insetup;
  1262.    inners[0].rotation = ss->rotation;
  1263.    outers->kind = lmap_ptr->outsetup;
  1264.    outers->rotation = ss->rotation;
  1265.  
  1266.    rot = 0;
  1267.  
  1268.    if (lmap_ptr->outer_rot) {
  1269.       outers->rotation--;
  1270.       rot = 011;
  1271.    }
  1272.  
  1273.    for (i=0; i<lmap_ptr->outlimit; i++) (void) copy_rot(outers, i, ss, lmap_ptr->mapout[i], rot);
  1274.  
  1275.    rot = 0;
  1276.  
  1277.    if (lmap_ptr->inner_rot) {
  1278.       inners[0].rotation--;
  1279.       rot = 011;
  1280.    }
  1281.  
  1282.    for (i=0; i<lmap_ptr->inlimit; i++) (void) copy_rot(&inners[0], i, ss, lmap_ptr->mapin[i], rot);
  1283.  
  1284.    if (lmap_ptr == &map_spec_star12) {
  1285.       *center_arity = 2;
  1286.       clear_people(&inners[1]);
  1287.       inners[1].setupflags = ss->setupflags;
  1288.       inners[1].kind = lmap_ptr->insetup;
  1289.       inners[1].rotation = ss->rotation;
  1290.       (void) copy_person(&inners[1], 0, ss, 10);
  1291.       (void) copy_person(&inners[1], 1, ss, 5);
  1292.       (void) copy_person(&inners[1], 2, ss, 8);
  1293.       (void) copy_person(&inners[1], 3, ss, 9);
  1294.    }
  1295.  
  1296.    /* Set the outer elongation to whatever elongation the outsides really had, as indicated
  1297.       by the map. */
  1298.  
  1299.    *outer_elongation = (lmap_ptr->mapelong + outers->rotation) & 1;
  1300.  
  1301.    /* If the concept is cross-concentric, we have to set the elongation to what
  1302.          the centers (who will, of course, be going to the outside) had.
  1303.       If the original centers are in a 2x2, we set it according to the orientation
  1304.          of the entire 2x4 they were in, so that they can think about whether they were
  1305.          in lines or columns and act accordingly.  If they were not in a 2x4, that is,
  1306.          the setup was a wing or galaxy, we set the elongation to -1 to indicate an
  1307.          error.  In such a case the centers won't be able to decide whether they were
  1308.          in lines or columns. */
  1309.  
  1310.    if (analyzer == schema_cross_concentric) {
  1311.       *xconc_elongation = *outer_elongation;
  1312.       switch (ss->kind) {
  1313.          case s_galaxy:
  1314.          case s_hrglass:
  1315.          case s_rigger:
  1316.          case s_3dmd:
  1317.          case s_3x1dmd:
  1318.             *xconc_elongation = -1;    /* Can't do this! */
  1319.             break;
  1320.          case s_crosswave:
  1321.          case s_qtag:
  1322.          case s3x4:
  1323.             *xconc_elongation ^= 1;
  1324.             break;
  1325.       }
  1326.    }
  1327.  
  1328.    finish:
  1329.  
  1330.    canonicalize_rotation(outers);
  1331.    canonicalize_rotation(&inners[0]);
  1332.    if (*center_arity == 2)
  1333.       canonicalize_rotation(&inners[1]);
  1334. }
  1335.  
  1336.  
  1337.  
  1338.  
  1339. int concwarn1x4table[] = {warn__xclineconc_perp, warn__lineconc_perp, warn__lineconc_par};
  1340. int concwarndmdtable[] = {warn__xcdmdconc_perp, warn__dmdconc_perp, warn__dmdconc_par};
  1341.  
  1342.  
  1343.  
  1344. extern void concentric_move(
  1345.    setup *ss,
  1346.    parse_block *parsein,
  1347.    parse_block *parseout,
  1348.    callspec_block *callspecin,
  1349.    callspec_block *callspecout,
  1350.    final_set final_conceptsin,
  1351.    final_set final_conceptsout,
  1352.    calldef_schema analyzer,
  1353.    defmodset modifiersin,
  1354.    defmodset modifiersout,
  1355.    setup *result)
  1356.  
  1357. {
  1358.    defmodset localmods, localmodsin, localmodsout;
  1359.    setup begin_inner[3];
  1360.    setup begin_outer;
  1361.    int begin_outer_elongation;
  1362.    int begin_xconc_elongation;
  1363.    int final_elongation;
  1364.    int center_arity;
  1365.    setup result_inner[3];
  1366.    setup result_outer;
  1367.    int i, k;
  1368.  
  1369.    setup_kind orig_inners_start_kind;    /* The original info about the people who STARTED on the inside. */
  1370.    int orig_inners_start_dirs;           /* We don't need rotation, since we will only use this if 2x2. */
  1371.    int orig_inners_start_directions[8];
  1372.  
  1373.    setup_kind orig_outers_start_kind;    /* The original info about the people who STARTED on the outside. */
  1374.    int orig_outers_start_dirs;           /* We don't need rotation, since we will only use this if 2x2. */
  1375.    int orig_outers_start_directions[8];
  1376.  
  1377.    setup_kind final_outers_start_kind;   /* The original info about the people who will FINISH on the outside. */
  1378.    int final_outers_start_dirs;          /* In case of cross-concentric, that's the original centers. */
  1379.    int *final_outers_start_directions;
  1380.  
  1381.    int final_outers_finish_dirs;         /* The final info about the people who FINISHED on the outside. */
  1382.    int final_outers_finish_directions[8];
  1383.  
  1384.    for (i=0; i<8; i++) {
  1385.       orig_inners_start_directions[i] =
  1386.       orig_outers_start_directions[i] =
  1387.       final_outers_finish_directions[i] = 0;
  1388.    }
  1389.  
  1390.    localmodsin = modifiersin;
  1391.    localmodsout = modifiersout;
  1392.  
  1393.    concentrify(ss, analyzer, begin_inner, &begin_outer, ¢er_arity, &begin_outer_elongation, &begin_xconc_elongation);
  1394.  
  1395.    /* Get initial info for the original ends. */
  1396.    orig_outers_start_dirs = 0;
  1397.    for (i=0; i<=setup_limits[begin_outer.kind]; i++) {
  1398.       int q = begin_outer.people[i].id1;
  1399.       orig_outers_start_dirs |= q;
  1400.       orig_outers_start_directions[(q >> 6) & 07] = q;
  1401.    }
  1402.    orig_outers_start_kind = begin_outer.kind;
  1403.  
  1404.    /* Get initial info for the original centers. */
  1405.    orig_inners_start_dirs = 0;
  1406.    for (i=0; i<=setup_limits[begin_inner[0].kind]; i++) {
  1407.       int q = begin_inner[0].people[i].id1;
  1408.       orig_inners_start_dirs |= q;
  1409.       orig_inners_start_directions[(q >> 6) & 07] = q;
  1410.    }
  1411.    orig_inners_start_kind = begin_inner[0].kind;
  1412.  
  1413.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric)) {
  1414.       setup temptemp = begin_inner[0];
  1415.       begin_inner[0] = begin_outer;
  1416.       begin_outer = temptemp;
  1417.  
  1418.       final_outers_start_kind = orig_inners_start_kind;
  1419.       final_outers_start_dirs = orig_inners_start_dirs;
  1420.       final_outers_start_directions = orig_inners_start_directions;
  1421.    }
  1422.    else {
  1423.       final_outers_start_kind = orig_outers_start_kind;
  1424.       final_outers_start_dirs = orig_outers_start_dirs;
  1425.       final_outers_start_directions = orig_outers_start_directions;
  1426.    }
  1427.  
  1428.    begin_inner[0].setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1429.    begin_inner[1].setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1430.    begin_inner[2].setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1431.  
  1432.    /* If the call turns out to be "detour", this will make it do just the ends part. */
  1433.    begin_outer.setupflags = ss->setupflags | SETUPFLAG__DISTORTED | SETUPFLAG__DOING_ENDS;
  1434.  
  1435.    /* There are two special pieces of information we now have that will help us decide where to
  1436.       put the outsides.  "Orig_outers_kind" tells what setup the outsides were originally in,
  1437.       and "begin_outer_elongation" is odd if the outsides were oriented vertically.
  1438.       "begin_outer_elongation" refers to absolute orientation, that is, "our" view of the
  1439.       setups, taking all rotations into account.  "Final_outers_start_dir" gives the individual
  1440.       orientations (absolute) of the people who are finishing on the outside.  Later, we will compute
  1441.       "final_outers_finish_dirs", telling how the individual people were oriented.  How we use all this
  1442.       information depends on many things that we will attend to below. */
  1443.  
  1444.    /* Giving one of the concept descriptor pointers as nil indicates that we don't want those people to do anything. */
  1445.  
  1446.    if (parsein) {
  1447.       for (k=0; k<center_arity; k++) {
  1448.          update_id_bits(&begin_inner[k]);
  1449.          move(&begin_inner[k], parsein, callspecin, final_conceptsin, FALSE, &result_inner[k]);
  1450.       }
  1451.    }
  1452.    else {
  1453.       for (k=0; k<center_arity; k++) {
  1454.          result_inner[k] = begin_inner[k];
  1455.          result_inner[k].setupflags = 0;
  1456.          /* Strip out the roll bits -- people who didn't move can't roll. */
  1457.          if (setup_limits[result_inner[k].kind] >= 0) {
  1458.             for (i=0; i<=setup_limits[result_inner[k].kind]; i++) {
  1459.                if (result_inner[k].people[i].id1) result_inner[k].people[i].id1 = (result_inner[k].people[i].id1 & (~ROLLBITS)) | ROLLBITM;
  1460.             }
  1461.          }
  1462.       }
  1463.    }
  1464.  
  1465.    if (parseout) {
  1466.       /* If the ends' starting setup is a 2x2, and we did not say "concentric" (indicated by
  1467.          the "concentric rules" flag being off), we mark the setup as elongated.  If the call
  1468.          turns out to be a 2-person call, the elongation will be checked against the pairings
  1469.          of people, and an error will be given if it isn't right.  This is what makes "cy-kick"
  1470.          illegal from diamonds, and "ends hinge" illegal from waves.  The reason this is turned
  1471.          off when the "concentric" concept is given is so that "concentric hinge" from waves,
  1472.          obnoxious as it may be, will be legal.
  1473.       We also turn it off if "demand lines" or "demand columns" has been given.  In that case,
  1474.          the database author knows what elongation is required and is taking responsibility
  1475.          for it.  This is what makes "scamper" and "divvy up" work.
  1476.       We also turn it off if this is reverse checkpoint.  In that case, the ends know exactly
  1477.          where they should go.  This is what makes "reverse checkpoint recycle by star thru"
  1478.          work from a DPT setup. */
  1479.  
  1480.       if (begin_outer.kind == s2x2 && analyzer != schema_rev_checkpoint &&
  1481.             !((dfm_conc_concentric_rules | dfm_conc_demand_lines | dfm_conc_demand_columns) & modifiersout) &&
  1482.             !(begin_outer_elongation & ~1)) {      /* We demand elongation be 0 or 1. */
  1483.          begin_outer.setupflags |= ((begin_outer_elongation+1) * SETUPFLAG__ELONGATE_BIT);
  1484.       }
  1485.  
  1486.       update_id_bits(&begin_outer);
  1487.       move(&begin_outer, parseout, callspecout, final_conceptsout, FALSE, &result_outer);
  1488.    }
  1489.    else {
  1490.       result_outer = begin_outer;
  1491.       result_outer.setupflags = 0;
  1492.       localmodsout |= dfm_conc_force_spots;      /* Make sure these people go to the same spots. */
  1493.       /* Strip out the roll bits -- people who didn't move can't roll. */
  1494.       if (setup_limits[result_outer.kind] >= 0) {
  1495.          for (i=0; i<=setup_limits[result_outer.kind]; i++) {
  1496.             if (result_outer.people[i].id1) result_outer.people[i].id1 = (result_outer.people[i].id1 & (~ROLLBITS)) | ROLLBITM;
  1497.          }
  1498.       }
  1499.    }
  1500.  
  1501.    /* If the call was something like "ends detour", the concentricity info was left in the
  1502.       setupflags during the execution of the call, so we have to pick it up to make sure
  1503.       that the necessary "demand" and "force" bits are honored. */
  1504.    localmodsout |= (begin_outer.setupflags & DFM_CONCENTRICITY_FLAG_MASK);
  1505.  
  1506.    /* Check whether the necessary "demand" conditions are met.  First, set "localmods"
  1507.       to the demand info for the call that the original ends did.  Where this comes from
  1508.       depends on whether the schema is cross concentric. */
  1509.  
  1510.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric)) {
  1511.       localmods = localmodsin;      /* Yes!  "In" describes the call for the original ends. */
  1512.    }
  1513.    else {
  1514.       localmods = localmodsout;
  1515.    }
  1516.  
  1517.    if ((dfm_conc_demand_lines & localmods) && (orig_outers_start_kind == s2x2)) {
  1518.       /* We make use of the fact that the setup, being a 2x2, is canonicalized. */
  1519.       if ((begin_outer_elongation < 0) ||
  1520.             (orig_outers_start_dirs & (1 << 3*(begin_outer_elongation & 1))))
  1521.          fail("Outsides must be as if in lines at start of this call.");
  1522.    }
  1523.    
  1524.    if ((dfm_conc_demand_columns & localmods) && (orig_outers_start_kind == s2x2)) {
  1525.       if ((begin_outer_elongation < 0) ||
  1526.             (orig_outers_start_dirs & (8 >> 3*(begin_outer_elongation & 1))))
  1527.          fail("Outsides must be as if in columns at start of this call.");
  1528.    }
  1529.  
  1530.    /* Now check whether there are any demands on the original centers.  The interpretation
  1531.       of "lines" and "columns" is slightly different in this case.  We apply the test only if
  1532.       the centers are in a 2x2, but we don't care about the outsides' setup, as long as it
  1533.       has a measurable elongation.  If the outsides are also in a 2x2, so that the whole setup
  1534.       is a 2x4, these tests will do just what they say -- they will check whether the centers
  1535.       believe they are in lines or columns.  However, if the outsides are in a 1x4, so the
  1536.       overall setup is a "rigger", we simply test the outsides' elongation.  In such a case
  1537.       "demand lines" means "demand outsides lateral to me". */
  1538.  
  1539.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric)) {
  1540.       localmods = localmodsout;
  1541.    }
  1542.    else {
  1543.       localmods = localmodsin;
  1544.    }
  1545.  
  1546.    if ((dfm_conc_demand_lines & localmods) && (orig_inners_start_kind == s2x2)) {
  1547.       if ((begin_outer_elongation < 0) ||
  1548.             (orig_inners_start_dirs & (1 << 3*(begin_outer_elongation & 1))))
  1549.          fail("Centers must be as if in lines at start of this call.");
  1550.    }
  1551.    
  1552.    if ((dfm_conc_demand_columns & localmods) && (orig_inners_start_kind == s2x2)) {
  1553.       if ((begin_outer_elongation < 0) ||
  1554.             (orig_inners_start_dirs & (8 >> 3*(begin_outer_elongation & 1))))
  1555.          fail("Centers must be as if in columns at start of this call.");
  1556.    }
  1557.  
  1558.    localmods = localmodsout;
  1559.  
  1560.    final_outers_finish_dirs = 0;
  1561.    for (i=0; i<=setup_limits[result_outer.kind]; i++) {
  1562.       int q = result_outer.people[i].id1;
  1563.       final_outers_finish_dirs |= q;
  1564.       final_outers_finish_directions[(q >> 6) & 07] = q;
  1565.    }
  1566.  
  1567.    /* Now final_outers_start_dirs and final_outers_finish_dirs tell whether outer peoples' orientations changed.
  1568.       This is only meaningful if outer setup is 2x2.  Note that, if the setups
  1569.       are 2x2's, canonicalization sets their rotation to zero, so the
  1570.       tbonetest quantities refer to absolute orientation. */
  1571.    
  1572.    /* The time has come to compute the elongation of the outsides in the final setup.
  1573.       This gets complicated if the outsides' final setup is a 2x2.  Among the
  1574.       procedures we could use are:
  1575.          (1) if the call is "checkpoint", go to spots with opposite elongation
  1576.             from the original outsides' elongation.  This is the "Hodson checkpoint
  1577.             rule", named after the caller who first used a consistent, methodical,
  1578.             and universal rule for the checkpoint concept.
  1579.          (2) if the call is "concentric", use the Hodson rule if the original setup
  1580.             was a 1x4 or diamond, or the "lines-to-lines, columns-to-columns" rule
  1581.             if the original setup was a 2x2.
  1582.          (3) if we have various definition flags, such as "force_lines" or
  1583.             "force_otherway", obey them.
  1584.       We will use information from several sources in carrying out these rules.
  1585.       The concentric concept will signify itself by turning on the "lines_lines"
  1586.       flag.  The checkpoint concept will signify itself by turning on the
  1587.       "force_otherway" flag.  The "parallel_conc_end" flag in the outsides' setup
  1588.       indicates that, if "concentric" or "checkpoint" are NOT being used, the call
  1589.       wants the outsides to maintain the same elongation as they had at the beginning.
  1590.       This is what makes "ends hinge" and "ends recycle" do their respective
  1591.       right things when called from a grand wave. */
  1592.  
  1593.    /* Default: the ends just keep their original elongation.  This will often
  1594.       mean that they stay on their spots. */
  1595.  
  1596.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric))
  1597.       final_elongation = begin_xconc_elongation;
  1598.    else
  1599.       final_elongation = begin_outer_elongation;
  1600.  
  1601.    /* Note: final_elongation might be -1 now, meaning that the people on the outside
  1602.       cannot determine their elongation from the original setup.  Unless their
  1603.       final setup is one that does not require knowing the value of final_elongation,
  1604.       it is an error. */
  1605.  
  1606.    if (result_outer.kind == nothing) {
  1607.       if (result_inner[0].kind == nothing) {
  1608.          result->kind = nothing;    /* If everyone is a phantom, it's simple. */
  1609.          return;
  1610.       }
  1611.  
  1612.       /* If the schema is one of the special ones, we will know what to do. */
  1613.       if (  analyzer == schema_conc_star ||
  1614.             analyzer == schema_ckpt_star ||
  1615.             analyzer == schema_conc_star12 ||
  1616.             analyzer == schema_conc_star16) {
  1617.                   ;        /* Take no action. */
  1618.       }
  1619.       else if (analyzer == schema_concentric_diamond_line) {
  1620.          if (ss->kind == s_wingedstar || ss->kind == s_wingedstar12 || ss->kind == s_wingedstar16) {
  1621.             final_elongation = ~ss->rotation & 1;
  1622.             result_outer.kind = s2x2;
  1623.             result_outer.rotation = 0;
  1624.             result_outer.setupflags = result_inner[0].setupflags;
  1625.             clear_people(&result_outer);
  1626.          }
  1627.          else
  1628.             goto no_end_err;
  1629.       }
  1630.       else {
  1631.          /* We may be in serious trouble -- we have to figure out what setup the ends
  1632.             finish in, and they are all phantoms.  We can save the day only if we
  1633.             can convince ourselves that they did the call "nothing".  We make use
  1634.             of the fact that "concentrify" did NOT flush them, so we still know
  1635.             what their starting setup was.
  1636.          This is what makes spilt phantom diamonds diamond chain through work
  1637.             from columns far apart.
  1638.          It is also needed to make 12 matrix relay the top work when everyone is
  1639.             in the stars.  If the center arity is not 1, we assume things will be OK. */
  1640.    
  1641.          result_outer = begin_outer;               /* Restore the original bunch of phantoms. */
  1642.          /* Make sure these people go to the same spots, and remove possibly misleading info. */
  1643.          localmods |= dfm_conc_force_spots;
  1644.          localmods &= ~(dfm_conc_force_lines | dfm_conc_force_columns | dfm_conc_force_otherway);
  1645.    
  1646.          if (parseout && callspecout && (callspecout->schema == schema_nothing))
  1647.             ;        /* It's OK. */
  1648.          else if (center_arity > 1)
  1649.             ;        /* It's OK. */
  1650.          else {
  1651.             /* We simply have no idea where the outsides should be.  We
  1652.                simply contract the setup to a 4-person setup (or whatever),
  1653.                throwing away the outsides completely.  If this was an
  1654.                "on your own", it may be possible to put things back together.
  1655.                This is what makes "1P2P; pass thru; ENDS leads latch on;
  1656.                ON YOUR OWN disband & snap the lock" work. */
  1657.  
  1658.             *result = result_inner[0];
  1659.             /* **** We should actually call normalize_concentric.  In fact, we should
  1660.                actually just fall into normal code.  However, normalize_concentric is,
  1661.                by its own admission, rather inept at dealing with these sorts of things. */
  1662.             return;
  1663.          }
  1664.       }
  1665.    }
  1666.    else if (result_inner[0].kind == nothing) {
  1667.       /* If the schema is one of the special ones, we will know what to do. */
  1668.       if (  analyzer == schema_conc_star ||
  1669.             analyzer == schema_ckpt_star ||
  1670.             analyzer == schema_conc_star12 ||
  1671.             analyzer == schema_conc_star16) {
  1672.                   ;        /* Take no action. */
  1673.       }
  1674.       /* If the ends are a 2x2, we just set the missing centers to a 2x2.
  1675.          The ends had better know their elongation, of course.  It shouldn't
  1676.          matter to the ends whether the phantoms in the center did something
  1677.          that leaves the whole setup as diamonds or as a 2x4.  (Some callers
  1678.          might think it matters (Hi, Clark!) but it doesn't matter to this program.)
  1679.          This is what makes spilt phantom diamonds diamond chain through work
  1680.          from a grand wave. */
  1681.       else if (result_outer.kind == s2x2 && center_arity == 1) {
  1682.          result_inner[0].kind = s2x2;
  1683.          clear_people(&result_inner[0]);
  1684.          result_inner[0].setupflags = 0;
  1685.          result_inner[0].rotation = 0;
  1686.       }
  1687.       /* If the ends are a 1x4, we just set the missing centers to a 1x4,
  1688.          so the entire setup is a 1x8.  Maybe the phantoms went to a 2x2,
  1689.          so the setup is really a rigger, but we don't care.  See the comment
  1690.          just above.  This is what makes "1P2P; pass thru; ENDS leads latch on;
  1691.          ON YOUR OWN disband & snap the lock" work. */
  1692.       else if (result_outer.kind == s1x4 && center_arity == 1) {
  1693.          result_inner[0].kind = s2x2;
  1694.          clear_people(&result_inner[0]);
  1695.          result_inner[0].setupflags = 0;
  1696.          result_inner[0].rotation = result_outer.rotation;
  1697.       }
  1698.       else {
  1699.          fail("Can't figure out ending setup for concentric call -- no centers.");
  1700.       }
  1701.    }
  1702.  
  1703. /* ***** We used to have this:
  1704.    if (result_outer.kind == s_short6) {
  1705.       switch (final_outers_start_kind) {
  1706.          case s_bone6:
  1707.             final_elongation ^= 1;     Natural elongation is wrong way!!
  1708.             break;
  1709.       }
  1710.    }
  1711. which is wrong.  The fact that short6 has a funny definition is taken care of in
  1712. normalize_concentric.  This code was making "outer 6 convert the triangle" fail
  1713. from a bone (heads left swing thru, side girl turn back).
  1714. ***** */
  1715.  
  1716.    if (result_outer.kind == s2x2) {
  1717.       int *concwarntable = (final_outers_start_kind == s1x4) ? concwarn1x4table : concwarndmdtable;
  1718.  
  1719.       switch (final_outers_start_kind) {
  1720.          case s1x4: case sdmd:
  1721.  
  1722.             /* Outers' call has gone from a 1x4 or diamond to a 2x2.  We change elongation if:
  1723.                (1) the "force_columns" or "force_lines" flag in the invocation takes precedence
  1724.                   over anything else.
  1725.                (2) the "concentric rules" flag is on (that flag is a euphemism for "the
  1726.                   concentric concept is explicitly in use here", which means we want
  1727.                   elongation perpendicular to the original 1x4, no matter what anyone says.)
  1728.                (3) the "force_otherway" invocation flag is on, meaning the database
  1729.                   really wants it this way.
  1730.                (4) the "par_conc_end" flag is OFF.  For 1x4->2x2 calls, this flag means
  1731.                   the call prefers the SAME elongation in the resulting 2x2.  The default,
  1732.                   absent this flag, is to change the elongation. */
  1733.  
  1734.             if (dfm_conc_force_lines & localmods) {
  1735.                if ((final_outers_finish_dirs & 011) == 011)
  1736.                   fail("Can't force ends to be as in lines - they are T-boned.");
  1737.                final_elongation = final_outers_finish_dirs & 1;
  1738.             }
  1739.             else if (dfm_conc_force_columns & localmods) {
  1740.                if ((final_outers_finish_dirs & 011) == 011)
  1741.                   fail("Can't force ends to be as in columns - they are T-boned.");
  1742.                final_elongation = (final_outers_finish_dirs+1) & 1;
  1743.             }
  1744.             else if ((dfm_conc_concentric_rules | dfm_conc_force_otherway) & localmods) {
  1745.                if (analyzer == schema_cross_concentric)
  1746.                   warn(concwarntable[0]);
  1747.                else
  1748.                   warn(concwarntable[1]);
  1749.  
  1750.                final_elongation ^= 1;
  1751.             }
  1752.             else {
  1753.                /* Get the elongation from the result setup, if possible. */
  1754.                unsigned long int newelong = ((result_outer.setupflags & RESULTFLAG__ELONGATE_MASK) / RESULTFLAG__ELONGATE_BIT) - 1;
  1755.  
  1756.                if (result_outer.setupflags & RESULTFLAG__ELONGATE_MASK) {
  1757.                   if (final_elongation == newelong) {
  1758.                      warn(concwarntable[2]);
  1759.                   }
  1760.                   else {
  1761.                      if (analyzer == schema_cross_concentric)
  1762.                         warn(concwarntable[0]);
  1763.                      else
  1764.                         warn(concwarntable[1]);
  1765.                   }
  1766.                }
  1767.  
  1768.                final_elongation = newelong;
  1769.             }
  1770.  
  1771.             break;
  1772.          case s2x2:
  1773.             /* If call went from 2x2 to 2x2, the rules are:
  1774.                First, check for "force_columns" or "force_lines" in the invocation.  This is not
  1775.                   a property of the call that we did, but of the way its parent (or the concept) invoked it.
  1776.                Second, check for "force_spots" or "force_otherway" in the invocation.  This is not
  1777.                   a property of the call that we did, but of the way its parent (or the concept) invoked it.
  1778.                Third, check for "lines_lines" in the invocation.  This is not
  1779.                   a property of the call that we did, but of the way its parent (or the concept) invoked it.
  1780.                   If the concept was "concentric", it will be on, of course.
  1781.                Finally, check the elongation bits in the result flags left over from the call.  These tell
  1782.                   whether to work to spots, or antispots, or whatever, based what the call was, and whether
  1783.                   it, or various sequential parts of it, had the "parallel_conc_end" flag on.
  1784.                If there are no elongation bits, we simply don't know waht to do.
  1785.  
  1786.                Note that the "ends do thus-and-so" concept does NOT set the lines_lines flag in the
  1787.                   invocation, so we work to spots unless the call says "parallel_conc_end".  Counter-rotate,
  1788.                   for example, says "parallel_conc_end", so it works to antispots. */
  1789.  
  1790.             if (dfm_conc_force_lines & localmods) {
  1791.                if ((final_outers_finish_dirs & 011) == 011)
  1792.                   fail("Can't force ends to be as in lines - they are T-boned.");
  1793.                final_elongation = final_outers_finish_dirs & 1;
  1794.             }
  1795.             else if (dfm_conc_force_columns & localmods) {
  1796.                if ((final_outers_finish_dirs & 011) == 011)
  1797.                   fail("Can't force ends to be as in columns - they are T-boned.");
  1798.                final_elongation = (final_outers_finish_dirs+1) & 1;
  1799.             }
  1800.             else if (dfm_conc_force_otherway & localmods)
  1801.                final_elongation ^= 1;
  1802.             else if (dfm_conc_force_spots & localmods)
  1803.                ;           /* It's OK the way it is. */
  1804.             else if (dfm_conc_concentric_rules & localmods) {       /* do "lines-to-lines / columns-to-columns" */
  1805.                int new_elongation = -1;
  1806.  
  1807.                for (i=0; i<8; i++) {
  1808.                   if (final_outers_finish_directions[i]) {
  1809.                      int t = (final_outers_start_directions[i] ^ final_outers_finish_directions[i] ^ final_elongation) & 1;
  1810.                      if (t != new_elongation) {
  1811.                         if (new_elongation >= 0)
  1812.                            fail("Sorry, outsides would have to go to a 'pinwheel', can't handle that.");
  1813.                         new_elongation = t;
  1814.                      }
  1815.                   }
  1816.                }
  1817.  
  1818.                /* The warning "warn__ends_work_to_spots" is now obsolete. */
  1819.  
  1820.                final_elongation = new_elongation;
  1821.             }
  1822.             else
  1823.                final_elongation = ((result_outer.setupflags & RESULTFLAG__ELONGATE_MASK) / RESULTFLAG__ELONGATE_BIT) - 1;
  1824.  
  1825.             break;
  1826.          default:
  1827.             fail("Don't recognize starting setup.");
  1828.       }
  1829.    }
  1830.  
  1831.    /* Now lossage in "final_elongation" may have been repaired.  If it is still
  1832.       negative, there may be trouble ahead. */
  1833.  
  1834.    normalize_concentric(analyzer, center_arity, result_inner, &result_outer, final_elongation, result);
  1835.    return;
  1836.  
  1837.    no_end_err:
  1838.    fail("Can't figure out ending setup for concentric call -- no ends.");
  1839. }
  1840.  
  1841.  
  1842. /* This overwrites its first argument setup. */
  1843. extern void merge_setups(setup *ss, setup *result)
  1844. {
  1845.    int i, r, rot, offs, limit, lim1, limhalf;
  1846.    setup res2copy;
  1847.    setup *res1, *res2;
  1848.  
  1849.    res2copy = *result;
  1850.    res1 = ss;
  1851.    res2 = &res2copy;
  1852.  
  1853.    canonicalize_rotation(res1);    /* Do we really need to do this before normalize_setup? */
  1854.    canonicalize_rotation(res2);
  1855.    normalize_setup(res1, normalize_before_merge);
  1856.    normalize_setup(res2, normalize_before_merge);
  1857.    canonicalize_rotation(res1);    /* We definitely need to do it now -- a 2x2 might have been created. */
  1858.    canonicalize_rotation(res2);
  1859.  
  1860.    /* Canonicalize the setups according to their kind.  This is a bit sleazy, since
  1861.       the enumeration order of setup kinds is supposed to be insignificant.  We depend in
  1862.       general on small setups being before larger ones.  In particular, we seem to require:
  1863.          s2x2 < s2x4
  1864.          s2x2 < s2x6
  1865.          s2x2 < s1x8
  1866.          s1x4 < s1x8
  1867.          s1x4 < s2x4
  1868.          s2x4 < s_c1phan
  1869.          s2x4 < s2x6
  1870.       You get the idea. */
  1871.  
  1872.    if (res2->kind < res1->kind) {
  1873.       res2 = ss;
  1874.       res1 = &res2copy;
  1875.    }
  1876.  
  1877.    result->rotation = res2->rotation;
  1878.  
  1879.    r = (res1->rotation - res2->rotation) & 3;
  1880.    rot = r * 011;
  1881.    
  1882.    if ((res1->kind == s2x4) && (res2->kind == s2x4) && (r&1)) {
  1883.       offs = r * 2;
  1884.       if ((((res1->people[0].id1 & res1->people[1].id1 & res1->people[4].id1 & res1->people[5].id1) |
  1885.                (res1->people[2].id1 & res1->people[3].id1 & res1->people[6].id1 & res1->people[7].id1)) & BIT_PERSON) &&
  1886.          (((res2->people[0].id1 & res2->people[1].id1 & res2->people[4].id1 & res2->people[5].id1) |
  1887.                (res2->people[2].id1 & res2->people[3].id1 & res2->people[6].id1 & res2->people[7].id1)) & BIT_PERSON)) {
  1888.          result->kind = s_c1phan;
  1889.          (void) copy_person(result, 10, res2, 5);
  1890.          (void) copy_person(result, 5, res2, 3);
  1891.          (void) copy_person(result, 13, res2, 7);
  1892.          (void) copy_person(result, 7, res2, 2);
  1893.          (void) copy_person(result, 2, res2, 1);
  1894.          (void) copy_person(result, 8, res2, 4);
  1895.          (void) copy_person(result, 15, res2, 6);
  1896.          clear_person(result, 1);
  1897.          clear_person(result, 3);
  1898.          clear_person(result, 4);
  1899.          clear_person(result, 6);
  1900.          clear_person(result, 9);
  1901.          clear_person(result, 11);
  1902.          clear_person(result, 12);
  1903.          clear_person(result, 14);
  1904.          install_rot(result, 11, res1, 0^offs, rot);
  1905.          install_rot(result, 9, res1, 1^offs, rot);
  1906.          install_rot(result, 4, res1, 2^offs, rot);
  1907.          install_rot(result, 6, res1, 3^offs, rot);
  1908.          install_rot(result, 3, res1, 4^offs, rot);
  1909.          install_rot(result, 1, res1, 5^offs, rot);
  1910.          install_rot(result, 12, res1, 6^offs, rot);
  1911.          install_rot(result, 14, res1, 7^offs, rot);
  1912.       }
  1913.       else {
  1914.          result->kind = s4x4;
  1915.          clear_person(result, 12);
  1916.          clear_person(result, 13);
  1917.          clear_person(result, 14);
  1918.          clear_person(result, 0);
  1919.          clear_person(result, 4);
  1920.          clear_person(result, 5);
  1921.          clear_person(result, 6);
  1922.          clear_person(result, 8);
  1923.          (void) copy_person(result, 10, res2, 0);
  1924.          (void) copy_person(result, 15, res2, 1);
  1925.          (void) copy_person(result, 3, res2, 2);
  1926.          (void) copy_person(result, 1, res2, 3);
  1927.          (void) copy_person(result, 2, res2, 4);
  1928.          (void) copy_person(result, 7, res2, 5);
  1929.          (void) copy_person(result, 11, res2, 6);
  1930.          (void) copy_person(result, 9, res2, 7);
  1931.  
  1932.          install_rot(result, 7, res1, 0^offs, rot);
  1933.          install_rot(result, 5, res1, 1^offs, rot);
  1934.          install_rot(result, 14, res1, 2^offs, rot);
  1935.          install_rot(result, 3, res1, 3^offs, rot);
  1936.          install_rot(result, 15, res1, 4^offs, rot);
  1937.          install_rot(result, 13, res1, 5^offs, rot);
  1938.          install_rot(result, 6, res1, 6^offs, rot);
  1939.          install_rot(result, 11, res1, 7^offs, rot);
  1940.       }
  1941.       return;
  1942.    }
  1943.    else if (res2->kind == s_c1phan && res1->kind == s2x4) {
  1944.       result->kind = s_c1phan;
  1945.       for (i=0; i<16; i++)
  1946.          (void) copy_person(result, i, res2, i);
  1947.  
  1948.       result->rotation -= r;
  1949.       canonicalize_rotation(result);
  1950.  
  1951.       install_person(result, 0, res1, 0);
  1952.       install_person(result, 2, res1, 1);
  1953.       install_person(result, 7, res1, 2);
  1954.       install_person(result, 5, res1, 3);
  1955.       install_person(result, 8, res1, 4);
  1956.       install_person(result, 10, res1, 5);
  1957.       install_person(result, 15, res1, 6);
  1958.       install_person(result, 13, res1, 7);
  1959.  
  1960.       result->rotation += r;
  1961.       canonicalize_rotation(result);
  1962.       return;
  1963.    }
  1964.    else if (res2->kind == s2x4 && res1->kind == s2x2) {
  1965.       result->kind = s2x4;
  1966.       for (i=0; i<8; i++)
  1967.          (void) copy_person(result, i, res2, i);
  1968.  
  1969.       res1->rotation += r;
  1970.       canonicalize_rotation(res1);
  1971.  
  1972.       install_person(result, 1, res1, 0);
  1973.       install_person(result, 2, res1, 1);
  1974.       install_person(result, 5, res1, 2);
  1975.       install_person(result, 6, res1, 3);
  1976.  
  1977.       canonicalize_rotation(result);
  1978.       return;
  1979.    }
  1980.    else if (res2->kind == s2x6 && res1->kind == s2x2) {
  1981.       result->kind = s2x6;
  1982.       for (i=0; i<12; i++)
  1983.          (void) copy_person(result, i, res2, i);
  1984.  
  1985.       res1->rotation += r;
  1986.       canonicalize_rotation(res1);
  1987.  
  1988.       install_person(result, 2, res1, 0);
  1989.       install_person(result, 3, res1, 1);
  1990.       install_person(result, 8, res1, 2);
  1991.       install_person(result, 9, res1, 3);
  1992.  
  1993.       canonicalize_rotation(result);
  1994.       return;
  1995.    }
  1996.    else if (res2->kind == s1x8 && res1->kind == s2x2 && (!(res2->people[2].id1 | res2->people[3].id1 | res2->people[6].id1 | res2->people[7].id1))) {
  1997.       res2->kind = s1x4;
  1998.       (void) copy_person(res2, 2, res2, 4);
  1999.       (void) copy_person(res2, 3, res2, 5);
  2000.       normalize_concentric(schema_concentric, 1, res1, res2, 0, result);
  2001.       return;
  2002.    }
  2003.    else if (res2->kind == s1x8 && res1->kind == s1x4 && (!(res2->people[2].id1 | res2->people[3].id1 | res2->people[6].id1 | res2->people[7].id1))) {
  2004.       res2->kind = s1x4;
  2005.       (void) copy_person(res2, 2, res2, 4);
  2006.       (void) copy_person(res2, 3, res2, 5);
  2007.       normalize_concentric(schema_concentric, 1, res1, res2, 0, result);
  2008.       return;
  2009.    }
  2010.    else if (res2->kind == s2x4 && res1->kind == s1x4 && (!(res2->people[1].id1 | res2->people[2].id1 | res2->people[5].id1 | res2->people[6].id1))) {
  2011.       int outer_elongation = res2->rotation & 1;
  2012.       res2->kind = s2x2;
  2013.       (void) copy_person(res2, 1, res2, 3);
  2014.       (void) copy_person(res2, 2, res2, 4);
  2015.       (void) copy_person(res2, 3, res2, 7);
  2016.       canonicalize_rotation(res2);
  2017.       normalize_concentric(schema_concentric, 1, res1, res2, outer_elongation, result);
  2018.       return;
  2019.    }
  2020.    else if (res2->kind == s2x6 && res1->kind == s2x4 && (r == 0)) {
  2021.       /* Because of canonicalization, we know that r = 0 unless
  2022.          they are 90 degrees from each other. */
  2023.       result->kind = s2x6;
  2024.       for (i=0; i<12; i++)
  2025.          (void) copy_person(result, i, res2, i);
  2026.  
  2027.       install_person(result, 1, res1, 0);
  2028.       install_person(result, 2, res1, 1);
  2029.       install_person(result, 3, res1, 2);
  2030.       install_person(result, 4, res1, 3);
  2031.       install_person(result, 7, res1, 4);
  2032.       install_person(result, 8, res1, 5);
  2033.       install_person(result, 9, res1, 6);
  2034.       install_person(result, 10, res1, 7);
  2035.       return;
  2036.    }
  2037.    
  2038.    /* This is sleazy. */
  2039.  
  2040.    limit = setup_limits[res1->kind];
  2041.    lim1 = limit+1;
  2042.    limhalf = lim1 >> 1;
  2043.  
  2044.    /* The only remaining hope is that the setups match and we can blindly combine them.  We require
  2045.       lim1 even because our 180 degree rotation wouldn't work for triangles. */
  2046.  
  2047.    if (res1->kind != res2->kind || r & 1 || limit < 0 || lim1 & 1)
  2048.       fail("Can't figure out result setup.");
  2049.    
  2050.    *result = *res2;
  2051.  
  2052.    if (r) {
  2053.       for (i=0; i<limit+1; i++)
  2054.          install_rot(result, i, res1, (i+limhalf) % lim1, rot);
  2055.    }
  2056.    else {
  2057.       for (i=0; i<limit+1; i++)
  2058.          install_person(result, i, res1, i);
  2059.    }
  2060. }
  2061.  
  2062.  
  2063. extern void on_your_own_move(
  2064.    setup *ss,
  2065.    parse_block *parseptr,
  2066.    setup *result)
  2067.  
  2068. {
  2069.    setup setup1, setup2, res1;
  2070.  
  2071.    if (ss->kind != s2x4) fail("Must have 2x4 setup for 'on your own'.");
  2072.    
  2073.    setup1 = *ss;              /* Get outers only. */
  2074.    clear_person(&setup1, 1);
  2075.    clear_person(&setup1, 2);
  2076.    clear_person(&setup1, 5);
  2077.    clear_person(&setup1, 6);
  2078.    setup1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  2079.    move(&setup1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  2080.    
  2081.    setup2 = *ss;              /* Get inners only. */
  2082.    clear_person(&setup2, 0);
  2083.    clear_person(&setup2, 3);
  2084.    clear_person(&setup2, 4);
  2085.    clear_person(&setup2, 7);
  2086.    setup2.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  2087.    move(&setup2, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, result);
  2088.    
  2089.    merge_setups(&res1, result);
  2090. }
  2091.  
  2092.  
  2093.  
  2094. extern void so_and_so_only_move(
  2095.    setup *ss,
  2096.    parse_block *parseptr,
  2097.    setup *result)
  2098.  
  2099. {
  2100.    selector_kind saved_selector;
  2101.    int i;
  2102.    long_boolean others;
  2103.    setup setup1, setup2, res1;
  2104.  
  2105.    saved_selector = current_selector;
  2106.    others = parseptr->concept->value.arg1;
  2107.    current_selector = parseptr->selector;
  2108.  
  2109.    setup1 = *ss;              /* designees */
  2110.    setup2 = *ss;              /* non-designees */
  2111.    
  2112.    if (setup_limits[ss->kind] < 0) fail("Can't identify people in this setup.");
  2113.    for (i=0; i<setup_limits[ss->kind]+1; i++) {
  2114.       if (ss->people[i].id1) {
  2115.          if (selectp(ss, i))
  2116.             clear_person(&setup2, i);
  2117.          else
  2118.             clear_person(&setup1, i);
  2119.       }
  2120.    }
  2121.    
  2122.    current_selector = saved_selector;
  2123.    
  2124.    normalize_setup(&setup1, normalize_before_isolated_call);
  2125.    normalize_setup(&setup2, normalize_before_isolated_call);
  2126.    setup1.setupflags = ss->setupflags;
  2127.    setup2.setupflags = ss->setupflags;
  2128.    
  2129.    move(&setup1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  2130.    
  2131.    if (others) {
  2132.       move(&setup2, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, result);
  2133.  
  2134.       if ((res1.setupflags ^ result->setupflags) & RESULTFLAG__DID_LAST_PART)
  2135.          fail("Two calls must use the same number of fractions.");
  2136.    
  2137.       result->setupflags |= res1.setupflags;
  2138.    }
  2139.    else {
  2140.       *result = setup2;
  2141.       result->setupflags = res1.setupflags;
  2142.    }
  2143.  
  2144.    merge_setups(&res1, result);
  2145. }
  2146.